summaryrefslogtreecommitdiff
path: root/old
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-01-01 19:31:12 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2017-01-01 19:31:12 +0100
commit69fe7b182a1eedfb75c611f7dd35fa60200426f4 (patch)
tree329a0c6cc9b06c23d8782ece09f0f7dfa9b16b13 /old
downloadcompilertests-69fe7b182a1eedfb75c611f7dd35fa60200426f4.tar.gz
compilertests-69fe7b182a1eedfb75c611f7dd35fa60200426f4.tar.bz2
initial checkin
Diffstat (limited to 'old')
-rw-r--r--old/C.bnf229
-rw-r--r--old/Makefile4
-rw-r--r--old/abc.ebnf36
-rw-r--r--old/cococpp/Action.cpp81
-rw-r--r--old/cococpp/Action.h59
-rw-r--r--old/cococpp/ArrayList.cpp79
-rw-r--r--old/cococpp/ArrayList.h52
-rw-r--r--old/cococpp/BitArray.cpp156
-rw-r--r--old/cococpp/BitArray.h68
-rw-r--r--old/cococpp/CharClass.cpp42
-rw-r--r--old/cococpp/CharClass.h48
-rw-r--r--old/cococpp/CharSet.cpp166
-rw-r--r--old/cococpp/CharSet.h68
-rw-r--r--old/cococpp/Coco.atg528
-rw-r--r--old/cococpp/Coco.cpp173
-rw-r--r--old/cococpp/Comment.cpp45
-rw-r--r--old/cococpp/Comment.h51
-rw-r--r--old/cococpp/Copyright.frame27
-rw-r--r--old/cococpp/DFA.cpp865
-rw-r--r--old/cococpp/DFA.h132
-rw-r--r--old/cococpp/Generator.cpp182
-rw-r--r--old/cococpp/Generator.h61
-rw-r--r--old/cococpp/Graph.h59
-rw-r--r--old/cococpp/HashTable.cpp115
-rw-r--r--old/cococpp/HashTable.h84
-rw-r--r--old/cococpp/Makefile11
-rw-r--r--old/cococpp/Melted.cpp39
-rw-r--r--old/cococpp/Melted.h51
-rw-r--r--old/cococpp/Node.cpp69
-rw-r--r--old/cococpp/Node.h86
-rw-r--r--old/cococpp/Parser.cpp925
-rw-r--r--old/cococpp/Parser.frame326
-rw-r--r--old/cococpp/Parser.h153
-rw-r--r--old/cococpp/ParserGen.cpp486
-rw-r--r--old/cococpp/ParserGen.h99
-rw-r--r--old/cococpp/Position.cpp37
-rw-r--r--old/cococpp/Position.h46
-rw-r--r--old/cococpp/Scanner.cpp833
-rw-r--r--old/cococpp/Scanner.frame897
-rw-r--r--old/cococpp/Scanner.h291
-rw-r--r--old/cococpp/Sets.h84
-rw-r--r--old/cococpp/SortedList.cpp141
-rw-r--r--old/cococpp/SortedList.h68
-rw-r--r--old/cococpp/State.cpp77
-rw-r--r--old/cococpp/State.h55
-rw-r--r--old/cococpp/StringBuilder.cpp88
-rw-r--r--old/cococpp/StringBuilder.h29
-rw-r--r--old/cococpp/Symbol.cpp61
-rw-r--r--old/cococpp/Symbol.h70
-rw-r--r--old/cococpp/Tab.cpp1248
-rw-r--r--old/cococpp/Tab.h245
-rw-r--r--old/cococpp/Target.cpp41
-rw-r--r--old/cococpp/Target.h48
-rw-r--r--old/cococpp/build.bat3
-rw-r--r--old/cococpp/build.sh4
-rw-r--r--old/cococpp/coc.bat1
-rw-r--r--old/cococpp/coc.sh2
-rw-r--r--old/cococpp/cygBuild.bat1
-rw-r--r--old/cococpp/mingwbuild.bat2
-rw-r--r--old/cococpp/zipsources.bat1
-rw-r--r--old/cocoebnf/EBNF.atg51
-rw-r--r--old/cocoebnf/Makefile15
-rw-r--r--old/cocoebnf/Parser.frame235
-rw-r--r--old/cocoebnf/Scanner.frame896
-rw-r--r--old/cocoebnf/ebnf.cpp24
-rw-r--r--old/cocoo0c/Makefile23
-rw-r--r--old/cocoo0c/Oberon0.atg45
-rw-r--r--old/cocoo0c/Oberon2.atg229
-rw-r--r--old/cocoo0c/Parser.frame235
-rw-r--r--old/cocoo0c/Parser.h203
-rw-r--r--old/cocoo0c/Scanner.frame896
-rw-r--r--old/cocoo0c/o0c.cpp24
-rw-r--r--old/cocoo0c/test0.o01
-rw-r--r--old/cocoo0c/test1.o03
-rw-r--r--old/cocoo0c/test2.o03
-rw-r--r--old/cocorepo/Expressions.hpp147
-rw-r--r--old/cocorepo/Makefile25
-rw-r--r--old/cocorepo/Parser.frame235
-rw-r--r--old/cocorepo/Parser.h203
-rw-r--r--old/cocorepo/Query.atg77
-rw-r--r--old/cocorepo/Scanner.frame896
-rw-r--r--old/cocorepo/query.cpp29
-rw-r--r--old/cocorepo/test0.data0
-rw-r--r--old/cocorepo/test0.qry3
-rw-r--r--old/cocorepo/test1.data0
-rw-r--r--old/cocorepo/test1.qry3
-rw-r--r--old/ebnf.c274
-rw-r--r--old/llvmtests/LINKS2
-rw-r--r--old/llvmtests/README5
-rw-r--r--old/llvmtests/hello.c7
-rw-r--r--old/parser.c180
-rw-r--r--old/test1.ebnf5
-rw-r--r--old/test2.ebnf5
-rw-r--r--old/test3.ebnf3
-rw-r--r--old/toy/LINKS2
-rw-r--r--old/toy/Makefile44
-rw-r--r--old/toy/codegen.cpp239
-rw-r--r--old/toy/codegen.hpp53
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org).htm1044
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/134242.js1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ClassDiagram.pngbin0 -> 53784 bytes
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ga.js64
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/highlight.js2
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image.pngbin0 -> 18819 bytes
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image1.pngbin0 -> 26793 bytes
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_002.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_003.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_004.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_005.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_006.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_007.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_008.php1
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/jquery.js154
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/pipeline.pngbin0 -> 8807 bytes
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/show_ads.js27
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/style.css151
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter.js52
-rw-r--r--old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter_icon.jpgbin0 -> 1925 bytes
-rw-r--r--old/toy/doc/os-createcompilerllvm1.txt1193
-rw-r--r--old/toy/doc/os-createcompilerllvm2.txt1341
-rw-r--r--old/toy/grammar.l34
-rw-r--r--old/toy/grammar.y103
-rw-r--r--old/toy/main.cpp35
-rw-r--r--old/toy/node.cpp118
-rw-r--r--old/toy/node.hpp168
-rw-r--r--old/toy/test.c23
127 files changed, 19866 insertions, 0 deletions
diff --git a/old/C.bnf b/old/C.bnf
new file mode 100644
index 0000000..3360513
--- /dev/null
+++ b/old/C.bnf
@@ -0,0 +1,229 @@
+<translation-unit> ::= {<external-declaration>}*
+
+<external-declaration> ::= <function-definition>
+ | <declaration>
+
+<function-definition> ::= {<declaration-specifier>}* <declarator> {<declaration>}* <compound-statement>
+
+<declaration-specifier> ::= <storage-class-specifier>
+ | <type-specifier>
+ | <type-qualifier>
+
+<storage-class-specifier> ::= auto
+ | register
+ | static
+ | extern
+ | typedef
+
+<type-specifier> ::= void
+ | char
+ | short
+ | int
+ | long
+ | float
+ | double
+ | signed
+ | unsigned
+ | <struct-or-union-specifier>
+ | <enum-specifier>
+ | <typedef-name>
+
+<struct-or-union-specifier> ::= <struct-or-union> <identifier> { {<struct-declaration>}+ }
+ | <struct-or-union> { {<struct-declaration>}+ }
+ | <struct-or-union> <identifier>
+
+<struct-or-union> ::= struct
+ | union
+
+<struct-declaration> ::= {<specifier-qualifier>}* <struct-declarator-list>
+
+<specifier-qualifier> ::= <type-specifier>
+ | <type-qualifier>
+
+<struct-declarator-list> ::= <struct-declarator>
+ | <struct-declarator-list> , <struct-declarator>
+
+<struct-declarator> ::= <declarator>
+ | <declarator> : <constant-expression>
+ | : <constant-expression>
+
+<declarator> ::= {<pointer>}? <direct-declarator>
+
+<pointer> ::= * {<type-qualifier>}* {<pointer>}?
+
+<type-qualifier> ::= const
+ | volatile
+
+<direct-declarator> ::= <identifier>
+ | ( <declarator> )
+ | <direct-declarator> [ {<constant-expression>}? ]
+ | <direct-declarator> ( <parameter-type-list> )
+ | <direct-declarator> ( {<identifier>}* )
+
+<constant-expression> ::= <conditional-expression>
+
+<conditional-expression> ::= <logical-or-expression>
+ | <logical-or-expression> ? <expression> : <conditional-expression>
+
+<logical-or-expression> ::= <logical-and-expression>
+ | <logical-or-expression || <logical-and-expression>
+
+<logical-and-expression> ::= <inclusive-or-expression>
+ | <logical-and-expression && <inclusive-or-expression>
+
+<inclusive-or-expression> ::= <exclusive-or-expression>
+ | <inclusive-or-expression> | <exclusive-or-expression>
+
+<exclusive-or-expression> ::= <and-expression>
+ | <exclusive-or-expression> ^ <and-expression>
+
+<and-expression> ::= <equality-expression>
+ | <and-expression> & <equality-expression>
+
+<equality-expression> ::= <relational-expression>
+ | <equality-expression> == <relational-expression>
+ | <equality-expression> != <relational-expression>
+
+<relational-expression> ::= <shift-expression>
+ | <relational-expression> < <shift-expression>
+ | <relational-expression> > <shift-expression>
+ | <relational-expression> <= <shift-expression>
+ | <relational-expression> >= <shift-expression>
+
+<shift-expression> ::= <additive-expression>
+ | <shift-expression> << <additive-expression>
+ | <shift-expression> >> <additive-expression>
+
+<additive-expression> ::= <multiplicative-expression>
+ | <additive-expression> + <multiplicative-expression>
+ | <additive-expression> - <multiplicative-expression>
+
+<multiplicative-expression> ::= <cast-expression>
+ | <multiplicative-expression> * <cast-expression>
+ | <multiplicative-expression> / <cast-expression>
+ | <multiplicative-expression> % <cast-expression>
+
+<cast-expression> ::= <unary-expression>
+ | ( <type-name> ) <cast-expression>
+
+<unary-expression> ::= <postfix-expression>
+ | ++ <unary-expression>
+ | -- <unary-expression>
+ | <unary-operator> <cast-expression>
+ | sizeof <unary-expression>
+ | sizeof <type-name>
+
+<postfix-expression> ::= <primary-expression>
+ | <postfix-expression> [ <expression> ]
+ | <postfix-expression> ( {<assignment-expression>}* )
+ | <postfix-expression> . <identifier>
+ | <postfix-expression> -> <identifier>
+ | <postfix-expression> ++
+ | <postfix-expression> --
+
+<primary-expression> ::= <identifier>
+ | <constant>
+ | <string>
+ | ( <expression> )
+
+<constant> ::= <integer-constant>
+ | <character-constant>
+ | <floating-constant>
+ | <enumeration-constant>
+
+<expression> ::= <assignment-expression>
+ | <expression> , <assignment-expression>
+
+<assignment-expression> ::= <conditional-expression>
+ | <unary-expression> <assignment-operator> <assignment-expression>
+
+<assignment-operator> ::= =
+ | *=
+ | /=
+ | %=
+ | +=
+ | -=
+ | <<=
+ | >>=
+ | &=
+ | ^=
+ | |=
+
+<unary-operator> ::= &
+ | *
+ | +
+ | -
+ | ~
+ | !
+
+<type-name> ::= {<specifier-qualifier>}+ {<abstract-declarator>}?
+
+<parameter-type-list> ::= <parameter-list>
+ | <parameter-list> , ...
+
+<parameter-list> ::= <parameter-declaration>
+ | <parameter-list> , <parameter-declaration>
+
+<parameter-declaration> ::= {<declaration-specifier>}+ <declarator>
+ | {<declaration-specifier>}+ <abstract-declarator>
+ | {<declaration-specifier>}+
+
+<abstract-declarator> ::= <pointer>
+ | <pointer> <direct-abstract-declarator>
+ | <direct-abstract-declarator>
+
+<direct-abstract-declarator> ::= ( <abstract-declarator> )
+ | {<direct-abstract-declarator>}? [ {<constant-expression>}? ]
+ | {<direct-abstract-declarator>}? ( {<parameter-type-list>|? )
+
+<enum-specifier> ::= enum <identifier> { <enumerator-list> }
+ | enum { <enumerator-list> }
+ | enum <identifier>
+
+<enumerator-list> ::= <enumerator>
+ | <enumerator-list> , <enumerator>
+
+<enumerator> ::= <identifier>
+ | <identifier> = <constant-expression>
+
+<typedef-name> ::= <identifier>
+
+<declaration> ::= {<declaration-specifier>}+ {<init-declarator>}*
+
+<init-declarator> ::= <declarator>
+ | <declarator> = <initializer>
+
+<initializer> ::= <assignment-expression>
+ | { <initializer-list> }
+ | { <initializer-list> , }
+
+<initializer-list> ::= <initializer>
+ | <initializer-list> , <initializer>
+
+<compound-statement> ::= { {<declaration>}* {<statement>}* }
+
+<statement> ::= <labeled-statement>
+ | <expression-statement>
+ | <compound-statement>
+ | <selection-statement>
+ | <iteration-statement>
+ | <jump-statement>
+
+<labeled-statement> ::= <identifier> : <statement>
+ | case <constant-expression> : <statement>
+ | default : <statement>
+
+<expression-statement> ::= {<expression>}? ;
+
+<selection-statement> ::= if ( <expression> ) <statement>
+ | if ( <expression> ) <statement> else <statement>
+ | switch ( <expression> ) <statement>
+
+<iteration-statement> ::= while ( <expression> ) <statement>
+ | do <statement> while ( <expression> ) ;
+ | for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
+
+<jump-statement> ::= goto <identifier> ;
+ | continue ;
+ | break ;
+ | return {<expression>}? ;
diff --git a/old/Makefile b/old/Makefile
new file mode 100644
index 0000000..8457782
--- /dev/null
+++ b/old/Makefile
@@ -0,0 +1,4 @@
+all: parser ebnf
+
+clean:
+ rm -f parser ebnf
diff --git a/old/abc.ebnf b/old/abc.ebnf
new file mode 100644
index 0000000..470f3f5
--- /dev/null
+++ b/old/abc.ebnf
@@ -0,0 +1,36 @@
+Program = { Variable-Declaration | Function-Declaration | Function-Definition } .
+Variable-Declaration = Type Ident ";" .
+Function-Declaration = Type Ident "(" Function-Arguments ")" ";" .
+Function-Definition = Type Ident "(" Function-Arguments ")" Function-Body .
+Function-Arguments = [ Type Index { "," Type Ident } ] .
+Type = "int" | "char" .
+Function-Body = Statement .
+Statement = "{" Statement "}"
+ | Type Ident [ "=" Expression ] ";"
+ | "return" Expression ";"
+ | "if" "(" Expression ")" Statement [ "else" Statement ]
+ | "while" "(" Expression ")" Statement
+ | Expression ";" .
+Expression = Equal-Expression .
+Equal-Expression =
+
+<expr> ::= <bitwise-expr>
+ | <bitwise-expr> = <expr>
+<bitwise-expr> ::= <eq-expr>
+ | <bitwise-expr> & <eq-expr>
+ | <bitwise-expr> | <eq-expr>
+<eq-expr> ::= <rel-expr>
+ | <eq-expr> == <rel-expr>
+ | <eq-expr> != <rel-expr>
+<rel-expr> ::= <shift-expr>
+ | <rel-expr> < <shift-expr>
+<shift-expr> ::= <add-expr>
+ | <shift-expr> << <add-expr>
+ | <shift-expr> >> <add-expr>
+<add-expr> ::= <postfix-expr>
+ | <add-expr> + <postfix-expr>
+ | <add-expr> - <postfix-expr>
+<postfix-expr> ::= <prim-expr>
+ | <postfix-expr> [ <expr> ]
+ | <postfix-expr> ( <expr> { "," <expr> } )
+<prim-expr> := <number> | <ident> | <string> | "(" <expr> ")"
diff --git a/old/cococpp/Action.cpp b/old/cococpp/Action.cpp
new file mode 100644
index 0000000..d6857b3
--- /dev/null
+++ b/old/cococpp/Action.cpp
@@ -0,0 +1,81 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Action.h"
+#include "Target.h"
+#include "CharSet.h"
+
+namespace Coco {
+
+Action::Action(int typ, int sym, int tc) {
+ this->target = NULL;
+ this->next = NULL;
+
+ this->typ = typ; this->sym = sym; this->tc = tc;
+}
+
+void Action::AddTarget(Target *t) { // add t to the action.targets
+ Target *last = NULL;
+ Target *p = target;
+ while (p != NULL && t->state->nr >= p->state->nr) {
+ if (t->state == p->state) return;
+ last = p; p = p->next;
+ }
+ t->next = p;
+ if (p == target) target = t; else last->next = t;
+}
+
+void Action::AddTargets(Action *a) {// add copy of a.targets to action.targets
+ for (Target *p = a->target; p != NULL; p = p->next) {
+ Target *t = new Target(p->state);
+ AddTarget(t);
+ }
+ if (a->tc == Node::contextTrans) tc = Node::contextTrans;
+}
+
+CharSet* Action::Symbols(Tab *tab) {
+ CharSet *s;
+ if (typ == Node::clas)
+ s = tab->CharClassSet(sym)->Clone();
+ else {
+ s = new CharSet(); s->Set(sym);
+ }
+ return s;
+}
+
+void Action::ShiftWith(CharSet *s, Tab *tab) {
+ if (s->Elements() == 1) {
+ typ = Node::chr; sym = s->First();
+ } else {
+ CharClass *c = tab->FindCharClass(s);
+ if (c == NULL) c = tab->NewCharClass(L"#", s); // class with dummy name
+ typ = Node::clas; sym = c->n;
+ }
+}
+
+}; // namespace
diff --git a/old/cococpp/Action.h b/old/cococpp/Action.h
new file mode 100644
index 0000000..4148b63
--- /dev/null
+++ b/old/cococpp/Action.h
@@ -0,0 +1,59 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_ACTION_H__)
+#define COCO_ACTION_H__
+
+#include "State.h"
+#include "Tab.h"
+
+namespace Coco {
+
+class Target;
+class CharSet;
+
+class Action // action of finite automaton
+{
+public:
+ int typ; // type of action symbol: clas, chr
+ int sym; // action symbol
+ int tc; // transition code: normalTrans, contextTrans
+ Target *target; // states reached from this action
+ Action *next;
+
+ Action(int typ, int sym, int tc);
+ void AddTarget(Target *t); // add t to the action.targets
+ void AddTargets(Action *a); // add copy of a.targets to action.targets
+ CharSet* Symbols(Tab *tab);
+ void ShiftWith(CharSet *s, Tab *tab);
+};
+
+}; // namespace
+
+
+#endif // !defined(COCO_ACTION_H__)
diff --git a/old/cococpp/ArrayList.cpp b/old/cococpp/ArrayList.cpp
new file mode 100644
index 0000000..0f50ddf
--- /dev/null
+++ b/old/cococpp/ArrayList.cpp
@@ -0,0 +1,79 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include "ArrayList.h"
+
+namespace Coco {
+
+ArrayList::ArrayList() {
+ Count = 0;
+ Capacity = 10;
+ Data = new void*[ Capacity ];
+}
+
+ArrayList::~ArrayList() {
+ delete [] Data;
+}
+
+void ArrayList::Add(void *value) {
+ if (Count < Capacity) {
+ Data[Count] = value;
+ Count++;
+ } else {
+ Capacity *= 2;
+ void** newData = new void*[Capacity];
+ for (int i=0; i<Count; i++) {
+ newData[i] = Data[i]; // copy
+ }
+ newData[Count] = value;
+ Count++;
+ delete [] Data;
+ Data = newData;
+ }
+}
+
+void ArrayList::Remove(void *value) {
+ for (int i=0; i<Count; i++) {
+ if (Data[i] == value) {
+ for (int j=i+1; j<Count; j++)
+ Data[j-1] = Data[j];
+ Count--;
+ break;
+ }
+ }
+}
+
+void* ArrayList::operator[]( int index )
+{
+ if (0<=index && index<Count)
+ return Data[index];
+ return NULL;
+}
+
+}; // namespace
diff --git a/old/cococpp/ArrayList.h b/old/cococpp/ArrayList.h
new file mode 100644
index 0000000..c91c032
--- /dev/null
+++ b/old/cococpp/ArrayList.h
@@ -0,0 +1,52 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_ARRAYLIST_H__)
+#define COCO_ARRAYLIST_H__
+
+namespace Coco {
+
+class ArrayList
+{
+public:
+ ArrayList();
+ virtual ~ArrayList();
+
+ void Add(void *value);
+ void Remove(void *value);
+ void* operator[](int index);
+
+ int Count;
+ int Capacity;
+private:
+ void** Data;
+};
+
+}; // namespace
+
+#endif // !defined(COCO_ARRAYLIST_H__)
diff --git a/old/cococpp/BitArray.cpp b/old/cococpp/BitArray.cpp
new file mode 100644
index 0000000..f578e46
--- /dev/null
+++ b/old/cococpp/BitArray.cpp
@@ -0,0 +1,156 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <memory.h>
+#include <stdio.h>
+#include "BitArray.h"
+
+namespace Coco {
+
+BitArray::BitArray(const int length, const bool defaultValue)
+{
+ Count = length;
+ Data = new unsigned char[ (length+7)>>3 ];
+ if (defaultValue)
+ memset(Data, 0xFF, (length+7)>>3);
+ else
+ memset(Data, 0x00, (length+7)>>3);
+}
+
+BitArray::BitArray(const BitArray &copy) {
+ Count = copy.Count;
+ Data = new unsigned char[ (copy.Count+7)>>3 ];
+ memcpy(Data, copy.Data, (copy.Count+7)>>3);
+}
+
+BitArray::~BitArray()
+{
+ delete [] Data;
+ Data = NULL;
+}
+
+int BitArray::getCount() {
+ return Count;
+}
+
+bool BitArray::Get(const int index) const
+{
+ return (Data[(index>>3)] & (1<<(index&7))) != 0;
+}
+
+void BitArray::Set(const int index, const bool value)
+{
+ if (value){
+ Data[(index>>3)] |= (1 << (index&7));
+ } else {
+ unsigned char mask = 0xFF;
+ mask ^= (1 << (index&7));
+ Data[(index>>3)] &= mask;
+ }
+}
+
+void BitArray::SetAll(const bool value)
+{
+ if (value)
+ memset(Data, 0xFF, (Count+7)>>3);
+ else
+ memset(Data, 0x00, (Count+7)>>3);
+}
+
+
+void BitArray::Not()
+{
+ for (int i=0; i<(Count+7)>>3; i++) {
+ Data[i] ^= 0xFF;
+ }
+}
+
+void BitArray::And(const BitArray *value)
+{
+ for (int i=0; (i<(Count+7)>>3) && (i<(value->Count+7)>>3); i++) {
+ Data[i] = (Data[i] & value->Data[i]);
+ }
+}
+
+void BitArray::Or(const BitArray *value)
+{
+ for (int i=0; (i<(Count+7)>>3) && (i<(value->Count+7)>>3); i++) {
+ Data[i] = (Data[i] | value->Data[i]);
+ }
+}
+
+void BitArray::Xor(const BitArray *value)
+{
+ for (int i=0; (i<(Count+7)>>3) && (i<(value->Count+7)>>3); i++) {
+ Data[i] = (Data[i] ^ value->Data[i]);
+ }
+}
+
+BitArray* BitArray::Clone() const
+{
+ BitArray *newBitArray = new BitArray(Count);
+ newBitArray->Count = Count;
+ memcpy(newBitArray->Data, Data, (Count+7)>>3);
+ return newBitArray;
+}
+
+bool BitArray::Equal(const BitArray *right) const
+{
+ if (Count != right->Count) {
+ return false;
+ }
+ for(int index = 0; index < Count; index++) {
+ if (Get(index) != right->Get(index)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BitArray::Overlaps(const BitArray *right) const
+{
+ for (int index = 0; index < Count; ++index) {
+ if (Get(index) && right->Get(index)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const BitArray &BitArray::operator=(const BitArray &right)
+{
+ if ( &right != this ) { // avoid self assignment
+ delete [] Data; // prevents memory leak
+ Count = right.Count;
+ Data = new unsigned char[ (Count+7)>>3 ];
+ memcpy(Data, right.Data, (Count+7)>>3);
+ }
+ return *this; // enables cascaded assignments
+}
+
+} // namespace
diff --git a/old/cococpp/BitArray.h b/old/cococpp/BitArray.h
new file mode 100644
index 0000000..31d0617
--- /dev/null
+++ b/old/cococpp/BitArray.h
@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_BITARRAY_H__)
+#define COCO_BITARRAY_H__
+
+namespace Coco {
+
+class BitArray
+{
+public:
+ BitArray(int length = 0, bool defaultValue = false) ;
+ BitArray(const BitArray &copy );
+ virtual ~BitArray();
+
+ int getCount();
+
+ bool Get(const int index) const;
+ void Set(const int index, const bool value);
+ void SetAll(const bool value);
+ bool Equal(const BitArray *right ) const;
+ bool Overlaps(const BitArray *right ) const;
+ bool operator[](const int index) const { return Get(index); };
+
+ const BitArray &operator=(const BitArray &right);
+
+ void Not();
+ void And(const BitArray *value);
+ void Or(const BitArray *value);
+ void Xor(const BitArray *value);
+
+ BitArray* Clone() const;
+
+private:
+ int Count;
+ unsigned char* Data;
+ void setMem(int length, bool value);
+
+};
+
+}
+
+#endif // !defined(COCO_BITARRAY_H__)
diff --git a/old/cococpp/CharClass.cpp b/old/cococpp/CharClass.cpp
new file mode 100644
index 0000000..deca847
--- /dev/null
+++ b/old/cococpp/CharClass.cpp
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "CharClass.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+CharClass::CharClass(const wchar_t* name, CharSet *s) {
+ this->name = coco_string_create(name); this->set = s;
+}
+
+CharClass::~CharClass() {
+ coco_string_delete(name);
+}
+
+}; // namespace
diff --git a/old/cococpp/CharClass.h b/old/cococpp/CharClass.h
new file mode 100644
index 0000000..f6cb461
--- /dev/null
+++ b/old/cococpp/CharClass.h
@@ -0,0 +1,48 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_CHARCLASS_H__)
+#define COCO_CHARCLASS_H__
+
+#include "CharSet.h"
+
+namespace Coco {
+
+class CharClass {
+public:
+ int n; // class number
+ wchar_t* name; // class name
+ CharSet *set; // set representing the class
+
+ CharClass(const wchar_t* name, CharSet *s);
+ virtual ~CharClass();
+};
+
+}; // namespace
+
+#endif // !defined(COCO_CHARCLASS_H__)
diff --git a/old/cococpp/CharSet.cpp b/old/cococpp/CharSet.cpp
new file mode 100644
index 0000000..04267eb
--- /dev/null
+++ b/old/cococpp/CharSet.cpp
@@ -0,0 +1,166 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "CharSet.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+bool CharSet::Get(int i) const {
+ for (CharSet::Range *p = head; p != NULL; p = p->next)
+ if (i < p->from) return false;
+ else if (i <= p->to) return true; // p.from <= i <= p.to
+ return false;
+}
+
+void CharSet::Set(int i) {
+ Range *cur = head, *prev = NULL;
+ while (cur != NULL && i >= cur->from-1) {
+ if (i <= cur->to + 1) { // (cur.from-1) <= i <= (cur.to+1)
+ if (i == cur->from - 1) cur->from--;
+ else if (i == cur->to + 1) {
+ cur->to++;
+ Range *next = cur->next;
+ if (next != NULL && cur->to == next->from - 1) {
+ cur->to = next->to;
+ cur->next = next->next;
+ delete next;
+ };
+ }
+ return;
+ }
+ prev = cur; cur = cur->next;
+ }
+ Range *n = new Range(i, i);
+ n->next = cur;
+ if (prev == NULL) head = n; else prev->next = n;
+}
+
+CharSet* CharSet::Clone() const {
+ CharSet *s = new CharSet();
+ Range *prev = NULL;
+ for (Range *cur = head; cur != NULL; cur = cur->next) {
+ Range *r = new Range(cur->from, cur->to);
+ if (prev == NULL) s->head = r; else prev->next = r;
+ prev = r;
+ }
+ return s;
+}
+
+bool CharSet::Equals(CharSet *s) const {
+ Range *p = head, *q = s->head;
+ while (p != NULL && q != NULL) {
+ if (p->from != q->from || p->to != q->to) return false;
+ p = p->next; q = q->next;
+ }
+ return p == q;
+}
+
+int CharSet::Elements() const {
+ int n = 0;
+ for (Range *p = head; p != NULL; p = p->next) n += p->to - p->from + 1;
+ return n;
+}
+
+int CharSet::First() const {
+ if (head != NULL) return head->from;
+ return -1;
+}
+
+void CharSet::Or(CharSet *s) {
+ for (Range *p = s->head; p != NULL; p = p->next)
+ for (int i = p->from; i <= p->to; i++) Set(i);
+}
+
+void CharSet::And(CharSet *s) {
+ CharSet *x = new CharSet();
+ Range *p = head;
+ while (p != NULL) {
+ for (int i = p->from; i <= p->to; i++)
+ if (s->Get(i)) x->Set(i);
+ Range *del = p;
+ p = p->next;
+ delete del;
+ }
+ head = x->head;
+ x->head = NULL;
+ delete x;
+}
+
+void CharSet::Subtract(CharSet *s) {
+ CharSet *x = new CharSet();
+ Range *p = head;
+ while (p != NULL) {
+ for (int i = p->from; i <= p->to; i++)
+ if (!s->Get(i)) x->Set(i);
+ Range *del = p;
+ p = p->next;
+ delete del;
+ }
+ head = x->head;
+ x->head = NULL;
+ delete x;
+}
+
+bool CharSet::Includes(CharSet *s) const {
+ for (Range *p = s->head; p != NULL; p = p->next)
+ for (int i = p->from; i <= p->to; i++)
+ if (!Get(i)) return false;
+ return true;
+}
+
+bool CharSet::Intersects(CharSet *s) const {
+ for (Range *p = s->head; p != NULL; p = p->next)
+ for (int i = p->from; i <= p->to; i++)
+ if (Get(i)) return true;
+ return false;
+}
+
+void CharSet::Clear() {
+ while (head != NULL) {
+ Range *del = head;
+ head = head->next;
+ delete del;
+ }
+}
+
+void CharSet::Fill() {
+ Clear();
+ head = new Range(0, COCO_WCHAR_MAX);
+}
+
+CharSet::~CharSet() {
+ Clear();
+}
+
+
+}
diff --git a/old/cococpp/CharSet.h b/old/cococpp/CharSet.h
new file mode 100644
index 0000000..4164d2d
--- /dev/null
+++ b/old/cococpp/CharSet.h
@@ -0,0 +1,68 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+#if !defined(COCO_CHARSET_H__)
+#define COCO_CHARSET_H__
+
+#include <stdio.h>
+
+namespace Coco {
+
+class CharSet {
+public:
+ class Range {
+ public:
+ int from;
+ int to;
+ Range *next;
+ Range(int from, int to) { this->from = from; this->to = to; next = NULL; };
+ };
+
+ Range *head;
+
+ CharSet() { head = NULL; };
+ virtual ~CharSet();
+
+ bool Get(int i) const;
+ void Set(int i);
+ CharSet* Clone() const;
+ bool Equals(CharSet *s) const;
+ int Elements() const;
+ int First() const;
+ void Or(CharSet *s);
+ void And(CharSet *s);
+ void Subtract(CharSet *s);
+ bool Includes(CharSet *s) const;
+ bool Intersects(CharSet *s) const;
+ void Clear();
+ void Fill();
+};
+
+} // namespace
+
+#endif // !defined(COCO_CHARSET_H__)
diff --git a/old/cococpp/Coco.atg b/old/cococpp/Coco.atg
new file mode 100644
index 0000000..b63b9a2
--- /dev/null
+++ b/old/cococpp/Coco.atg
@@ -0,0 +1,528 @@
+/*-------------------------------------------------------------------------
+Coco.ATG -- Attributed Grammar
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------
+ compile with:
+ Coco Coco.ATG -namespace Coco
+-------------------------------------------------------------------------*/
+$namespace=Coco
+
+#include "Tab.h"
+#include "DFA.h"
+#include "ParserGen.h"
+
+COMPILER Coco
+
+ int id;
+ int str;
+
+ FILE* trace; // other Coco objects referenced in this ATG
+ Tab *tab;
+ DFA *dfa;
+ ParserGen *pgen;
+
+ bool genScanner;
+ wchar_t* tokenString; // used in declarations of literal tokens
+ wchar_t* noString; // used in declarations of literal tokens
+
+ // This method will be called by the contructor if it exits.
+ // This support is specific to the C++ version of Coco/R.
+ void Init() {
+ tab = NULL;
+ dfa = NULL;
+ pgen = NULL;
+ id = 0;
+ str = 1;
+ tokenString = NULL;
+ noString = coco_string_create(L"-none-");
+ }
+
+ // Uncomment this method if cleanup is necessary,
+ // this method will be called by the destructor if it exists.
+ // This support is specific to the C++ version of Coco/R.
+ // void Destroy() {
+ // nothing to do
+ // }
+/*-------------------------------------------------------------------------*/
+
+CHARACTERS
+ letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_".
+ digit = "0123456789".
+ cr = '\r'.
+ lf = '\n'.
+ tab = '\t'.
+ stringCh = ANY - '"' - '\\' - cr - lf.
+ charCh = ANY - '\'' - '\\' - cr - lf.
+ printable = '\u0020' .. '\u007e'.
+ hex = "0123456789abcdef".
+
+TOKENS
+ ident = letter { letter | digit }.
+ number = digit { digit }.
+ string = '"' { stringCh | '\\' printable } '"'.
+ badString = '"' { stringCh | '\\' printable } (cr | lf).
+ char = '\'' ( charCh | '\\' printable { hex } ) '\''.
+
+PRAGMAS
+ ddtSym = '$' { digit | letter }. (. tab->SetDDT(la->val); .)
+ optionSym = '$' letter { letter } '='
+ { digit | letter
+ | '-' | '.' | ':'
+ }. (. tab->SetOption(la->val); .)
+
+
+COMMENTS FROM "/*" TO "*/" NESTED
+COMMENTS FROM "//" TO lf
+
+IGNORE cr + lf + tab
+
+/*-------------------------------------------------------------------------*/
+
+PRODUCTIONS
+
+Coco (. Symbol *sym; Graph *g, *g1, *g2; wchar_t* gramName = NULL; CharSet *s; .)
+=
+ (. int beg = la->pos; int line = la->line; .)
+ { // this section can be used
+ // for #include statements
+ ANY
+ } (. if (la->pos != beg) {
+ pgen->usingPos = new Position(beg, t->pos + coco_string_length(t->val), 0, line);
+ }
+ .)
+
+ "COMPILER" (. genScanner = true;
+ tab->ignored = new CharSet(); .)
+ ident (. gramName = coco_string_create(t->val);
+ beg = la->pos;
+ line = la->line;
+ .)
+ { ANY } (. tab->semDeclPos = new Position(beg, la->pos, 0, line); .)
+ [ "IGNORECASE" (. dfa->ignoreCase = true; .) ] /* pdt */
+ [ "CHARACTERS" { SetDecl }]
+ [ "TOKENS" { TokenDecl<Node::t> }]
+ [ "PRAGMAS" { TokenDecl<Node::pr> }]
+ { "COMMENTS" (. bool nested = false; .)
+ "FROM" TokenExpr<g1>
+ "TO" TokenExpr<g2>
+ [ "NESTED" (. nested = true; .)
+ ] (. dfa->NewComment(g1->l, g2->l, nested); .)
+ }
+ { "IGNORE" Set<s> (. tab->ignored->Or(s); .)
+ }
+
+ SYNC
+ "PRODUCTIONS" (. if (genScanner) dfa->MakeDeterministic();
+ tab->DeleteNodes();
+ .)
+ { ident (. sym = tab->FindSym(t->val);
+ bool undef = (sym == NULL);
+ if (undef) sym = tab->NewSym(Node::nt, t->val, t->line);
+ else {
+ if (sym->typ == Node::nt) {
+ if (sym->graph != NULL) SemErr(L"name declared twice");
+ } else SemErr(L"this symbol kind not allowed on left side of production");
+ sym->line = t->line;
+ }
+ bool noAttrs = (sym->attrPos == NULL);
+ sym->attrPos = NULL;
+ .)
+ [ AttrDecl<sym> ] (. if (!undef)
+ if (noAttrs != (sym->attrPos == NULL))
+ SemErr(L"attribute mismatch between declaration and use of this symbol");
+ .)
+ [ SemText<.sym->semPos.> ] WEAK
+ '='
+ Expression<g> (. sym->graph = g->l;
+ tab->Finish(g);
+ .)
+ WEAK
+ '.'
+ }
+ "END" ident (. if (!coco_string_equal(gramName, t->val))
+ SemErr(L"name does not match grammar name");
+ tab->gramSy = tab->FindSym(gramName);
+ if (tab->gramSy == NULL)
+ SemErr(L"missing production for grammar name");
+ else {
+ sym = tab->gramSy;
+ if (sym->attrPos != NULL)
+ SemErr(L"grammar symbol must not have attributes");
+ }
+ tab->noSym = tab->NewSym(Node::t, L"???", 0); // noSym gets highest number
+ tab->SetupAnys();
+ tab->RenumberPragmas();
+ if (tab->ddt[2]) tab->PrintNodes();
+ if (errors->count == 0) {
+ wprintf(L"checking\n");
+ tab->CompSymbolSets();
+ if (tab->ddt[7]) tab->XRef();
+ if (tab->GrammarOk()) {
+ wprintf(L"parser");
+ pgen->WriteParser();
+ if (genScanner) {
+ wprintf(L" + scanner");
+ dfa->WriteScanner();
+ if (tab->ddt[0]) dfa->PrintStates();
+ }
+ wprintf(L" generated\n");
+ if (tab->ddt[8]) pgen->WriteStatistics();
+ }
+ }
+ if (tab->ddt[6]) tab->PrintSymbolTable();
+ .)
+ '.'
+.
+
+/*------------------------------------------------------------------------------------*/
+
+SetDecl (. CharSet *s; .)
+=
+ ident (. wchar_t *name = coco_string_create(t->val);
+ CharClass *c = tab->FindCharClass(name);
+ if (c != NULL) SemErr(L"name declared twice");
+ .)
+ '=' Set<s> (. if (s->Elements() == 0) SemErr(L"character set must not be empty");
+ tab->NewCharClass(name, s);
+ .)
+ '.'
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Set<CharSet* &s> (. CharSet *s2; .)
+=
+ SimSet<s>
+ { '+' SimSet<s2> (. s->Or(s2); .)
+ | '-' SimSet<s2> (. s->Subtract(s2); .)
+ }
+.
+
+/*------------------------------------------------------------------------------------*/
+
+SimSet<CharSet* &s> (. int n1, n2; .)
+= (. s = new CharSet(); .)
+( ident (. CharClass *c = tab->FindCharClass(t->val);
+ if (c == NULL) SemErr(L"undefined name"); else s->Or(c->set);
+ .)
+| string (.
+ wchar_t *subName2 = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ wchar_t *name = tab->Unescape(subName2);
+ coco_string_delete(subName2);
+ wchar_t ch;
+ int len = coco_string_length(name);
+ for(int i=0; i < len; i++) {
+ ch = name[i];
+ if (dfa->ignoreCase) {
+ if ((L'A' <= ch) && (ch <= L'Z')) ch = ch - (L'A' - L'a'); // ch.ToLower()
+ }
+ s->Set(ch);
+ }
+ coco_string_delete(name);
+ .)
+| Char<n1> (. s->Set(n1); .)
+ [ ".." Char<n2> (. for (int i = n1; i <= n2; i++) s->Set(i); .)
+ ]
+| "ANY" (. s = new CharSet(); s->Fill(); .)
+)
+.
+
+/*--------------------------------------------------------------------------------------*/
+
+Char<int &n>
+=
+ char (. n = 0;
+ wchar_t* subName = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ wchar_t* name = tab->Unescape(subName);
+ coco_string_delete(subName);
+
+ // "<= 1" instead of "== 1" to allow the escape sequence '\0' in c++
+ if (coco_string_length(name) <= 1) n = name[0];
+ else SemErr(L"unacceptable character value");
+ coco_string_delete(name);
+ if (dfa->ignoreCase && (((wchar_t) n) >= 'A') && (((wchar_t) n) <= 'Z')) n += 32;
+ .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+TokenDecl<int typ> (. wchar_t* name = NULL; int kind; Symbol *sym; Graph *g; .)
+=
+ Sym<name, kind> (. sym = tab->FindSym(name);
+ if (sym != NULL) SemErr(L"name declared twice");
+ else {
+ sym = tab->NewSym(typ, name, t->line);
+ sym->tokenKind = Symbol::fixedToken;
+ }
+ tokenString = NULL;
+ .)
+ SYNC
+ ( '=' TokenExpr<g> '.' (. if (kind == str) SemErr(L"a literal must not be declared with a structure");
+ tab->Finish(g);
+ if (tokenString == NULL || coco_string_equal(tokenString, noString))
+ dfa->ConvertToStates(g->l, sym);
+ else { // TokenExpr is a single string
+ if ((*(tab->literals))[tokenString] != NULL)
+ SemErr(L"token string declared twice");
+ tab->literals->Set(tokenString, sym);
+ dfa->MatchLiteral(tokenString, sym);
+ }
+ .)
+ | (. if (kind == id) genScanner = false;
+ else dfa->MatchLiteral(sym->name, sym);
+ .)
+ )
+ [ SemText<.sym->semPos.> (. if (typ != Node::pr) SemErr(L"semantic action not allowed here"); .)
+ ]
+.
+
+/*------------------------------------------------------------------------------------*/
+
+AttrDecl<Symbol *sym>
+=
+ '<' (. int beg = la->pos; int col = la->col; int line = la->line; .)
+ { ANY
+ | badString (. SemErr(L"bad string in attributes"); .)
+ }
+ '>' (. if (t->pos > beg)
+ sym->attrPos = new Position(beg, t->pos, col, line); .)
+| "<." (. int beg = la->pos; int col = la->col; int line = la->line; .)
+ { ANY
+ | badString (. SemErr(L"bad string in attributes"); .)
+ }
+ ".>" (. if (t->pos > beg)
+ sym->attrPos = new Position(beg, t->pos, col, line); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Expression<Graph* &g> (. Graph *g2; .)
+=
+ Term<g> (. bool first = true; .)
+ { WEAK
+ '|'
+ Term<g2> (. if (first) { tab->MakeFirstAlt(g); first = false; }
+ tab->MakeAlternative(g, g2);
+ .)
+ }
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Term<Graph* &g> (. Graph *g2; Node *rslv = NULL; g = NULL; .)
+=
+( [ (. rslv = tab->NewNode(Node::rslv, (Symbol*)NULL, la->line); .)
+ Resolver<.rslv->pos.> (. g = new Graph(rslv); .)
+ ]
+ Factor<g2> (. if (rslv != NULL) tab->MakeSequence(g, g2);
+ else g = g2; .)
+ { Factor<g2> (. tab->MakeSequence(g, g2); .)
+ }
+| (. g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0)); .)
+) (. if (g == NULL) // invalid start of Term
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0)); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Factor<Graph* &g> (. wchar_t* name = NULL; int kind; Position *pos; bool weak = false;
+ g = NULL;
+ .)
+=
+( [ "WEAK" (. weak = true; .)
+ ]
+ Sym<name, kind> (. Symbol *sym = tab->FindSym(name);
+ if (sym == NULL && kind == str)
+ sym = (Symbol*)((*(tab->literals))[name]);
+ bool undef = (sym == NULL);
+ if (undef) {
+ if (kind == id)
+ sym = tab->NewSym(Node::nt, name, 0); // forward nt
+ else if (genScanner) {
+ sym = tab->NewSym(Node::t, name, t->line);
+ dfa->MatchLiteral(sym->name, sym);
+ } else { // undefined string in production
+ SemErr(L"undefined string in production");
+ sym = tab->eofSy; // dummy
+ }
+ }
+ int typ = sym->typ;
+ if (typ != Node::t && typ != Node::nt)
+ SemErr(L"this symbol kind is not allowed in a production");
+ if (weak) {
+ if (typ == Node::t) typ = Node::wt;
+ else SemErr(L"only terminals may be weak");
+ }
+ Node *p = tab->NewNode(typ, sym, t->line);
+ g = new Graph(p);
+ .)
+ [ Attribs<p> (. if (kind != id) SemErr(L"a literal must not have attributes"); .)
+ ] (. if (undef)
+ sym->attrPos = p->pos; // dummy
+ else if ((p->pos == NULL) != (sym->attrPos == NULL))
+ SemErr(L"attribute mismatch between declaration and use of this symbol");
+ .)
+| '(' Expression<g> ')'
+| '[' Expression<g> ']' (. tab->MakeOption(g); .)
+| '{' Expression<g> '}' (. tab->MakeIteration(g); .)
+| SemText<pos> (. Node *p = tab->NewNode(Node::sem, (Symbol*)NULL, 0);
+ p->pos = pos;
+ g = new Graph(p);
+ .)
+| "ANY" (. Node *p = tab->NewNode(Node::any, (Symbol*)NULL, 0); // p.set is set in tab->SetupAnys
+ g = new Graph(p);
+ .)
+| "SYNC" (. Node *p = tab->NewNode(Node::sync, (Symbol*)NULL, 0);
+ g = new Graph(p);
+ .)
+) (. if (g == NULL) // invalid start of Factor
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0));
+ .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Resolver<Position* &pos>
+=
+ "IF" "(" (. int beg = la->pos; int col = la->col; int line = la->line; .)
+ Condition (. pos = new Position(beg, t->pos, col, line); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Condition = { "(" Condition | ANY } ")" .
+
+/*------------------------------------------------------------------------------------*/
+
+TokenExpr<Graph* &g> (. Graph *g2; .)
+=
+ TokenTerm<g> (. bool first = true; .)
+ { WEAK
+ '|'
+ TokenTerm<g2> (. if (first) { tab->MakeFirstAlt(g); first = false; }
+ tab->MakeAlternative(g, g2);
+ .)
+ }
+.
+
+/*------------------------------------------------------------------------------------*/
+
+TokenTerm<Graph* &g> (. Graph *g2; .)
+=
+ TokenFactor<g>
+ { TokenFactor<g2> (. tab->MakeSequence(g, g2); .)
+ }
+ [ "CONTEXT"
+ '(' TokenExpr<g2> (. tab->SetContextTrans(g2->l); dfa->hasCtxMoves = true;
+ tab->MakeSequence(g, g2); .)
+ ')'
+ ]
+.
+
+/*------------------------------------------------------------------------------------*/
+
+TokenFactor<Graph* &g> (. wchar_t* name = NULL; int kind; .)
+=
+ (. g = NULL; .)
+( Sym<name, kind> (. if (kind == id) {
+ CharClass *c = tab->FindCharClass(name);
+ if (c == NULL) {
+ SemErr(L"undefined name");
+ c = tab->NewCharClass(name, new CharSet());
+ }
+ Node *p = tab->NewNode(Node::clas, (Symbol*)NULL, 0); p->val = c->n;
+ g = new Graph(p);
+ tokenString = coco_string_create(noString);
+ } else { // str
+ g = tab->StrToGraph(name);
+ if (tokenString == NULL) tokenString = coco_string_create(name);
+ else tokenString = coco_string_create(noString);
+ }
+ .)
+| '(' TokenExpr<g> ')'
+| '[' TokenExpr<g> ']' (. tab->MakeOption(g); tokenString = coco_string_create(noString); .)
+| '{' TokenExpr<g> '}' (. tab->MakeIteration(g); tokenString = coco_string_create(noString); .)
+) (. if (g == NULL) // invalid start of TokenFactor
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0)); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Sym<wchar_t* &name, int &kind>
+= (. name = coco_string_create(L"???"); kind = id; .)
+( ident (. kind = id; coco_string_delete(name); name = coco_string_create(t->val); .)
+| (string (. coco_string_delete(name); name = coco_string_create(t->val); .)
+ | char (.
+ wchar_t *subName = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ coco_string_delete(name);
+ name = coco_string_create_append(L"\"", subName);
+ coco_string_delete(subName);
+ coco_string_merge(name, L"\"");
+ .)
+ ) (. kind = str;
+ if (dfa->ignoreCase) {
+ wchar_t *oldName = name;
+ name = coco_string_create_lower(name);
+ coco_string_delete(oldName);
+ }
+ if (coco_string_indexof(name, ' ') >= 0)
+ SemErr(L"literal tokens must not contain blanks"); .)
+)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+Attribs<Node *p>
+=
+ '<' (. int beg = la->pos; int col = la->col; int line = la->line; .)
+ { ANY
+ | badString (. SemErr(L"bad string in attributes"); .)
+ }
+ '>' (. if (t->pos > beg) p->pos = new Position(beg, t->pos, col, line); .)
+| "<." (. int beg = la->pos; int col = la->col; int line = la->line; .)
+ { ANY
+ | badString (. SemErr(L"bad string in attributes"); .)
+ }
+ ".>" (. if (t->pos > beg) p->pos = new Position(beg, t->pos, col, line); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+SemText<Position* &pos>
+=
+ "(." (. int beg = la->pos; int col = la->col; int line = t->line; .)
+ { ANY
+ | badString (. SemErr(L"bad string in semantic action"); .)
+ | "(." (. SemErr(L"missing end of previous semantic action"); .)
+ }
+ ".)" (. pos = new Position(beg, t->pos, col, line); .)
+.
+
+/*------------------------------------------------------------------------------------*/
+
+END Coco.
diff --git a/old/cococpp/Coco.cpp b/old/cococpp/Coco.cpp
new file mode 100644
index 0000000..fdbc782
--- /dev/null
+++ b/old/cococpp/Coco.cpp
@@ -0,0 +1,173 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------
+ Trace output options
+ 0 | A: prints the states of the scanner automaton
+ 1 | F: prints the First and Follow sets of all nonterminals
+ 2 | G: prints the syntax graph of the productions
+ 3 | I: traces the computation of the First sets
+ 4 | J: prints the sets associated with ANYs and synchronisation sets
+ 6 | S: prints the symbol table (terminals, nonterminals, pragmas)
+ 7 | X: prints a cross reference list of all syntax symbols
+ 8 | P: prints statistics about the Coco run
+
+ Trace output can be switched on by the pragma
+ $ { digit | letter }
+ in the attributed grammar or as a command-line option
+ -------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+#include "Scanner.h"
+#include "Parser.h"
+#include "Tab.h"
+
+using namespace Coco;
+
+#ifdef _WIN32
+int wmain(int argc, wchar_t *argv[]) {
+#elif defined __GNUC__
+int main(int argc, char *argv_[]) {
+ wchar_t ** argv = new wchar_t*[argc];
+ for (int i = 0; i < argc; ++i) {
+ argv[i] = coco_string_create(argv_[i]);
+ }
+#else
+#error unknown compiler!
+#endif
+
+ wprintf(L"Coco/R (Jan 02, 2012)\n");
+
+ wchar_t *srcName = NULL, *nsName = NULL, *frameDir = NULL, *ddtString = NULL, *traceFileName = NULL;
+ wchar_t *outDir = NULL;
+ char *chTrFileName = NULL;
+ bool emitLines = false;
+
+ for (int i = 1; i < argc; i++) {
+ if (coco_string_equal(argv[i], L"-namespace") && i < argc - 1) nsName = coco_string_create(argv[++i]);
+ else if (coco_string_equal(argv[i], L"-frames") && i < argc - 1) frameDir = coco_string_create(argv[++i]);
+ else if (coco_string_equal(argv[i], L"-trace") && i < argc - 1) ddtString = coco_string_create(argv[++i]);
+ else if (coco_string_equal(argv[i], L"-o") && i < argc - 1) outDir = coco_string_create_append(argv[++i], L"/");
+ else if (coco_string_equal(argv[i], L"-lines")) emitLines = true;
+ else srcName = coco_string_create(argv[i]);
+ }
+
+#if defined __GNUC__
+ for (int i = 0; i < argc; ++i) {
+ coco_string_delete(argv[i]);
+ }
+ delete [] argv; argv = NULL;
+#endif
+
+ if (argc > 0 && srcName != NULL) {
+ int pos = coco_string_lastindexof(srcName, '/');
+ if (pos < 0) pos = coco_string_lastindexof(srcName, '\\');
+ wchar_t* file = coco_string_create(srcName);
+ wchar_t* srcDir = coco_string_create(srcName, 0, pos+1);
+
+ Coco::Scanner *scanner = new Coco::Scanner(file);
+ Coco::Parser *parser = new Coco::Parser(scanner);
+
+ traceFileName = coco_string_create_append(srcDir, L"trace.txt");
+ chTrFileName = coco_string_create_char(traceFileName);
+
+ if ((parser->trace = fopen(chTrFileName, "w")) == NULL) {
+ wprintf(L"-- could not open %hs\n", chTrFileName);
+ exit(1);
+ }
+
+ parser->tab = new Coco::Tab(parser);
+ parser->dfa = new Coco::DFA(parser);
+ parser->pgen = new Coco::ParserGen(parser);
+
+ parser->tab->srcName = coco_string_create(srcName);
+ parser->tab->srcDir = coco_string_create(srcDir);
+ parser->tab->nsName = nsName ? coco_string_create(nsName) : NULL;
+ parser->tab->frameDir = coco_string_create(frameDir);
+ parser->tab->outDir = coco_string_create(outDir != NULL ? outDir : srcDir);
+ parser->tab->emitLines = emitLines;
+
+ if (ddtString != NULL) parser->tab->SetDDT(ddtString);
+
+ parser->Parse();
+
+ fclose(parser->trace);
+
+ // obtain the FileSize
+ parser->trace = fopen(chTrFileName, "r");
+ fseek(parser->trace, 0, SEEK_END);
+ long fileSize = ftell(parser->trace);
+ fclose(parser->trace);
+ if (fileSize == 0) {
+ remove(chTrFileName);
+ } else {
+ wprintf(L"trace output is in %hs\n", chTrFileName);
+ }
+
+ wprintf(L"%d errors detected\n", parser->errors->count);
+ if (parser->errors->count != 0) {
+ exit(1);
+ }
+
+ delete parser->pgen;
+ delete parser->dfa;
+ delete parser->tab;
+ delete parser;
+ delete scanner;
+ coco_string_delete(file);
+ coco_string_delete(srcDir);
+ } else {
+ wprintf(L"Usage: Coco Grammar.ATG {Option}\n");
+ wprintf(L"Options:\n");
+ wprintf(L" -namespace <namespaceName>\n");
+ wprintf(L" -frames <frameFilesDirectory>\n");
+ wprintf(L" -trace <traceString>\n");
+ wprintf(L" -o <outputDirectory>\n");
+ wprintf(L" -lines\n");
+ wprintf(L"Valid characters in the trace string:\n");
+ wprintf(L" A trace automaton\n");
+ wprintf(L" F list first/follow sets\n");
+ wprintf(L" G print syntax graph\n");
+ wprintf(L" I trace computation of first sets\n");
+ wprintf(L" J list ANY and SYNC sets\n");
+ wprintf(L" P print statistics\n");
+ wprintf(L" S list symbol table\n");
+ wprintf(L" X list cross reference table\n");
+ wprintf(L"Scanner.frame and Parser.frame files needed in ATG directory\n");
+ wprintf(L"or in a directory specified in the -frames option.\n");
+ }
+
+ coco_string_delete(srcName);
+ coco_string_delete(nsName);
+ coco_string_delete(frameDir);
+ coco_string_delete(ddtString);
+ coco_string_delete(chTrFileName);
+ coco_string_delete(traceFileName);
+
+ return 0;
+}
diff --git a/old/cococpp/Comment.cpp b/old/cococpp/Comment.cpp
new file mode 100644
index 0000000..7c91746
--- /dev/null
+++ b/old/cococpp/Comment.cpp
@@ -0,0 +1,45 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Comment.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+Comment::Comment(wchar_t* start, wchar_t* stop, bool nested) {
+ this->start = coco_string_create(start);
+ this->stop = coco_string_create(stop);
+ this->nested = nested;
+}
+
+Comment::~Comment() {
+ coco_string_delete(start);
+ coco_string_delete(stop);
+}
+
+}; // namespace
diff --git a/old/cococpp/Comment.h b/old/cococpp/Comment.h
new file mode 100644
index 0000000..ffc1c82
--- /dev/null
+++ b/old/cococpp/Comment.h
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_COMMENT_H__)
+#define COCO_COMMENT_H__
+
+#include <wchar.h>
+
+namespace Coco {
+
+class Comment // info about comment syntax
+{
+public:
+ wchar_t* start;
+ wchar_t* stop;
+ bool nested;
+ Comment *next;
+
+ Comment(wchar_t* start, wchar_t* stop, bool nested);
+ virtual ~Comment();
+
+};
+
+}; // namespace
+
+#endif // !defined(COCO_COMMENT_H__)
diff --git a/old/cococpp/Copyright.frame b/old/cococpp/Copyright.frame
new file mode 100644
index 0000000..5c74f7e
--- /dev/null
+++ b/old/cococpp/Copyright.frame
@@ -0,0 +1,27 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
diff --git a/old/cococpp/DFA.cpp b/old/cococpp/DFA.cpp
new file mode 100644
index 0000000..cf4414f
--- /dev/null
+++ b/old/cococpp/DFA.cpp
@@ -0,0 +1,865 @@
+/*-------------------------------------------------------------------------
+DFA -- Generation of the Scanner Automaton
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <wchar.h>
+#include "DFA.h"
+#include "Tab.h"
+#include "Parser.h"
+#include "BitArray.h"
+#include "Scanner.h"
+#include "Generator.h"
+
+namespace Coco {
+
+//---------- Output primitives
+wchar_t* DFA::Ch(wchar_t ch) {
+ wchar_t* format = new wchar_t[10];
+ if (ch < L' ' || ch >= 127 || ch == L'\'' || ch == L'\\')
+ coco_swprintf(format, 10, L"%d\0", (int) ch);
+ else
+ coco_swprintf(format, 10, L"L'%lc'\0", (int) ch);
+ return format;
+}
+
+wchar_t* DFA::ChCond(wchar_t ch) {
+ wchar_t* format = new wchar_t[20];
+ wchar_t* res = Ch(ch);
+ coco_swprintf(format, 20, L"ch == %ls\0", res);
+ delete [] res;
+ return format;
+}
+
+void DFA::PutRange(CharSet *s) {
+ for (CharSet::Range *r = s->head; r != NULL; r = r->next) {
+ if (r->from == r->to) {
+ wchar_t *from = Ch((wchar_t) r->from);
+ fwprintf(gen, L"ch == %ls", from);
+ delete [] from;
+ } else if (r->from == 0) {
+ wchar_t *to = Ch((wchar_t) r->to);
+ fwprintf(gen, L"ch <= %ls", to);
+ delete [] to;
+ } else {
+ wchar_t *from = Ch((wchar_t) r->from);
+ wchar_t *to = Ch((wchar_t) r->to);
+ fwprintf(gen, L"(ch >= %ls && ch <= %ls)", from, to);
+ delete [] from; delete [] to;
+ }
+ if (r->next != NULL) fwprintf(gen, L" || ");
+ }
+}
+
+
+//---------- State handling
+
+State* DFA::NewState() {
+ State *s = new State(); s->nr = ++lastStateNr;
+ if (firstState == NULL) firstState = s; else lastState->next = s;
+ lastState = s;
+ return s;
+}
+
+void DFA::NewTransition(State *from, State *to, int typ, int sym, int tc) {
+ Target *t = new Target(to);
+ Action *a = new Action(typ, sym, tc); a->target = t;
+ from->AddAction(a);
+ if (typ == Node::clas) curSy->tokenKind = Symbol::classToken;
+}
+
+void DFA::CombineShifts() {
+ State *state;
+ Action *a, *b, *c;
+ CharSet *seta, *setb;
+ for (state = firstState; state != NULL; state = state->next) {
+ for (a = state->firstAction; a != NULL; a = a->next) {
+ b = a->next;
+ while (b != NULL)
+ if (a->target->state == b->target->state && a->tc == b->tc) {
+ seta = a->Symbols(tab); setb = b->Symbols(tab);
+ seta->Or(setb);
+ a->ShiftWith(seta, tab);
+ c = b; b = b->next; state->DetachAction(c);
+ } else b = b->next;
+ }
+ }
+}
+
+void DFA::FindUsedStates(State *state, BitArray *used) {
+ if ((*used)[state->nr]) return;
+ used->Set(state->nr, true);
+ for (Action *a = state->firstAction; a != NULL; a = a->next)
+ FindUsedStates(a->target->state, used);
+}
+
+void DFA::DeleteRedundantStates() {
+ //State *newState = new State[State::lastNr + 1];
+ State **newState = (State**) malloc (sizeof(State*) * (lastStateNr + 1));
+ BitArray *used = new BitArray(lastStateNr + 1);
+ FindUsedStates(firstState, used);
+ // combine equal final states
+ for (State *s1 = firstState->next; s1 != NULL; s1 = s1->next) // firstState cannot be final
+ if ((*used)[s1->nr] && s1->endOf != NULL && s1->firstAction == NULL && !(s1->ctx))
+ for (State *s2 = s1->next; s2 != NULL; s2 = s2->next)
+ if ((*used)[s2->nr] && s1->endOf == s2->endOf && s2->firstAction == NULL && !(s2->ctx)) {
+ used->Set(s2->nr, false); newState[s2->nr] = s1;
+ }
+
+ State *state;
+ for (state = firstState; state != NULL; state = state->next)
+ if ((*used)[state->nr])
+ for (Action *a = state->firstAction; a != NULL; a = a->next)
+ if (!((*used)[a->target->state->nr]))
+ a->target->state = newState[a->target->state->nr];
+ // delete unused states
+ lastState = firstState; lastStateNr = 0; // firstState has number 0
+ for (state = firstState->next; state != NULL; state = state->next)
+ if ((*used)[state->nr]) {state->nr = ++lastStateNr; lastState = state;}
+ else lastState->next = state->next;
+ free (newState);
+ delete used;
+}
+
+State* DFA::TheState(Node *p) {
+ State *state;
+ if (p == NULL) {state = NewState(); state->endOf = curSy; return state;}
+ else return p->state;
+}
+
+void DFA::Step(State *from, Node *p, BitArray *stepped) {
+ if (p == NULL) return;
+ stepped->Set(p->n, true);
+
+ if (p->typ == Node::clas || p->typ == Node::chr) {
+ NewTransition(from, TheState(p->next), p->typ, p->val, p->code);
+ } else if (p->typ == Node::alt) {
+ Step(from, p->sub, stepped); Step(from, p->down, stepped);
+ } else if (p->typ == Node::iter) {
+ if (tab->DelSubGraph(p->sub)) {
+ parser->SemErr(L"contents of {...} must not be deletable");
+ return;
+ }
+ if (p->next != NULL && !((*stepped)[p->next->n])) Step(from, p->next, stepped);
+ Step(from, p->sub, stepped);
+ if (p->state != from) {
+ BitArray *newStepped = new BitArray(tab->nodes->Count);
+ Step(p->state, p, newStepped);
+ delete newStepped;
+ }
+ } else if (p->typ == Node::opt) {
+ if (p->next != NULL && !((*stepped)[p->next->n])) Step(from, p->next, stepped);
+ Step(from, p->sub, stepped);
+ }
+}
+
+// Assigns a state n.state to every node n. There will be a transition from
+// n.state to n.next.state triggered by n.val. All nodes in an alternative
+// chain are represented by the same state.
+// Numbering scheme:
+// - any node after a chr, clas, opt, or alt, must get a new number
+// - if a nested structure starts with an iteration the iter node must get a new number
+// - if an iteration follows an iteration, it must get a new number
+void DFA::NumberNodes(Node *p, State *state, bool renumIter) {
+ if (p == NULL) return;
+ if (p->state != NULL) return; // already visited;
+ if ((state == NULL) || ((p->typ == Node::iter) && renumIter)) state = NewState();
+ p->state = state;
+ if (tab->DelGraph(p)) state->endOf = curSy;
+
+ if (p->typ == Node::clas || p->typ == Node::chr) {
+ NumberNodes(p->next, NULL, false);
+ } else if (p->typ == Node::opt) {
+ NumberNodes(p->next, NULL, false);
+ NumberNodes(p->sub, state, true);
+ } else if (p->typ == Node::iter) {
+ NumberNodes(p->next, state, true);
+ NumberNodes(p->sub, state, true);
+ } else if (p->typ == Node::alt) {
+ NumberNodes(p->next, NULL, false);
+ NumberNodes(p->sub, state, true);
+ NumberNodes(p->down, state, renumIter);
+ }
+}
+
+void DFA::FindTrans (Node *p, bool start, BitArray *marked) {
+ if (p == NULL || (*marked)[p->n]) return;
+ marked->Set(p->n, true);
+ if (start) {
+ BitArray *stepped = new BitArray(tab->nodes->Count);
+ Step(p->state, p, stepped); // start of group of equally numbered nodes
+ delete stepped;
+ }
+
+ if (p->typ == Node::clas || p->typ == Node::chr) {
+ FindTrans(p->next, true, marked);
+ } else if (p->typ == Node::opt) {
+ FindTrans(p->next, true, marked); FindTrans(p->sub, false, marked);
+ } else if (p->typ == Node::iter) {
+ FindTrans(p->next, false, marked); FindTrans(p->sub, false, marked);
+ } else if (p->typ == Node::alt) {
+ FindTrans(p->sub, false, marked); FindTrans(p->down, false, marked);
+ }
+}
+
+void DFA::ConvertToStates(Node *p, Symbol *sym) {
+ curGraph = p; curSy = sym;
+ if (tab->DelGraph(curGraph)) {
+ parser->SemErr(L"token might be empty");
+ return;
+ }
+ NumberNodes(curGraph, firstState, true);
+ FindTrans(curGraph, true, new BitArray(tab->nodes->Count));
+ if (p->typ == Node::iter) {
+ BitArray *stepped = new BitArray(tab->nodes->Count);
+ Step(firstState, p, stepped);
+ delete stepped;
+ }
+}
+
+// match string against current automaton; store it either as a fixedToken or as a litToken
+void DFA::MatchLiteral(wchar_t* s, Symbol *sym) {
+ wchar_t *subS = coco_string_create(s, 1, coco_string_length(s)-2);
+ s = tab->Unescape(subS);
+ coco_string_delete(subS);
+ int i, len = coco_string_length(s);
+ State *state = firstState;
+ Action *a = NULL;
+ for (i = 0; i < len; i++) { // try to match s against existing DFA
+ a = FindAction(state, s[i]);
+ if (a == NULL) break;
+ state = a->target->state;
+ }
+ // if s was not totally consumed or leads to a non-final state => make new DFA from it
+ if (i != len || state->endOf == NULL) {
+ state = firstState; i = 0; a = NULL;
+ dirtyDFA = true;
+ }
+ for (; i < len; i++) { // make new DFA for s[i..len-1]
+ State *to = NewState();
+ NewTransition(state, to, Node::chr, s[i], Node::normalTrans);
+ state = to;
+ }
+ coco_string_delete(s);
+ Symbol *matchedSym = state->endOf;
+ if (state->endOf == NULL) {
+ state->endOf = sym;
+ } else if (matchedSym->tokenKind == Symbol::fixedToken || (a != NULL && a->tc == Node::contextTrans)) {
+ // s matched a token with a fixed definition or a token with an appendix that will be cut off
+ wchar_t format[200];
+ coco_swprintf(format, 200, L"tokens %ls and %ls cannot be distinguished", sym->name, matchedSym->name);
+ parser->SemErr(format);
+ } else { // matchedSym == classToken || classLitToken
+ matchedSym->tokenKind = Symbol::classLitToken;
+ sym->tokenKind = Symbol::litToken;
+ }
+}
+
+void DFA::SplitActions(State *state, Action *a, Action *b) {
+ Action *c; CharSet *seta, *setb, *setc;
+ seta = a->Symbols(tab); setb = b->Symbols(tab);
+ if (seta->Equals(setb)) {
+ a->AddTargets(b);
+ state->DetachAction(b);
+ } else if (seta->Includes(setb)) {
+ setc = seta->Clone(); setc->Subtract(setb);
+ b->AddTargets(a);
+ a->ShiftWith(setc, tab);
+ } else if (setb->Includes(seta)) {
+ setc = setb->Clone(); setc->Subtract(seta);
+ a->AddTargets(b);
+ b->ShiftWith(setc, tab);
+ } else {
+ setc = seta->Clone(); setc->And(setb);
+ seta->Subtract(setc);
+ setb->Subtract(setc);
+ a->ShiftWith(seta, tab);
+ b->ShiftWith(setb, tab);
+ c = new Action(0, 0, Node::normalTrans); // typ and sym are set in ShiftWith
+ c->AddTargets(a);
+ c->AddTargets(b);
+ c->ShiftWith(setc, tab);
+ state->AddAction(c);
+ }
+}
+
+bool DFA::Overlap(Action *a, Action *b) {
+ CharSet *seta, *setb;
+ if (a->typ == Node::chr)
+ if (b->typ == Node::chr) return (a->sym == b->sym);
+ else {setb = tab->CharClassSet(b->sym); return setb->Get(a->sym);}
+ else {
+ seta = tab->CharClassSet(a->sym);
+ if (b->typ == Node::chr) return seta->Get(b->sym);
+ else {setb = tab->CharClassSet(b->sym); return seta->Intersects(setb);}
+ }
+}
+
+bool DFA::MakeUnique(State *state) { // return true if actions were split
+ bool changed = false;
+ for (Action *a = state->firstAction; a != NULL; a = a->next)
+ for (Action *b = a->next; b != NULL; b = b->next)
+ if (Overlap(a, b)) {
+ SplitActions(state, a, b);
+ changed = true;
+ }
+ return changed;
+}
+
+void DFA::MeltStates(State *state) {
+ bool changed, ctx;
+ BitArray *targets;
+ Symbol *endOf;
+ for (Action *action = state->firstAction; action != NULL; action = action->next) {
+ if (action->target->next != NULL) {
+ GetTargetStates(action, targets, endOf, ctx);
+ Melted *melt = StateWithSet(targets);
+ if (melt == NULL) {
+ State *s = NewState(); s->endOf = endOf; s->ctx = ctx;
+ for (Target *targ = action->target; targ != NULL; targ = targ->next)
+ s->MeltWith(targ->state);
+ do {changed = MakeUnique(s);} while (changed);
+ melt = NewMelted(targets, s);
+ }
+ action->target->next = NULL;
+ action->target->state = melt->state;
+ }
+ }
+}
+
+void DFA::FindCtxStates() {
+ for (State *state = firstState; state != NULL; state = state->next)
+ for (Action *a = state->firstAction; a != NULL; a = a->next)
+ if (a->tc == Node::contextTrans) a->target->state->ctx = true;
+}
+
+void DFA::MakeDeterministic() {
+ State *state;
+ bool changed;
+ lastSimState = lastState->nr;
+ maxStates = 2 * lastSimState; // heuristic for set size in Melted.set
+ FindCtxStates();
+ for (state = firstState; state != NULL; state = state->next)
+ do {changed = MakeUnique(state);} while (changed);
+ for (state = firstState; state != NULL; state = state->next)
+ MeltStates(state);
+ DeleteRedundantStates();
+ CombineShifts();
+}
+
+void DFA::PrintStates() {
+ fwprintf(trace, L"\n");
+ fwprintf(trace, L"---------- states ----------\n");
+ for (State *state = firstState; state != NULL; state = state->next) {
+ bool first = true;
+ if (state->endOf == NULL) fwprintf(trace, L" ");
+ else {
+ wchar_t *paddedName = tab->Name(state->endOf->name);
+ fwprintf(trace, L"E(%12s)", paddedName);
+ coco_string_delete(paddedName);
+ }
+ fwprintf(trace, L"%3d:", state->nr);
+ if (state->firstAction == NULL) fwprintf(trace, L"\n");
+ for (Action *action = state->firstAction; action != NULL; action = action->next) {
+ if (first) {fwprintf(trace, L" "); first = false;} else fwprintf(trace, L" ");
+
+ if (action->typ == Node::clas) fwprintf(trace, L"%ls", ((CharClass*)(*tab->classes)[action->sym])->name);
+ else fwprintf(trace, L"%3s", Ch((wchar_t)action->sym));
+ for (Target *targ = action->target; targ != NULL; targ = targ->next) {
+ fwprintf(trace, L"%3d", targ->state->nr);
+ }
+ if (action->tc == Node::contextTrans) fwprintf(trace, L" context\n"); else fwprintf(trace, L"\n");
+ }
+ }
+ fwprintf(trace, L"\n---------- character classes ----------\n");
+ tab->WriteCharClasses();
+}
+
+//---------------------------- actions --------------------------------
+
+Action* DFA::FindAction(State *state, wchar_t ch) {
+ for (Action *a = state->firstAction; a != NULL; a = a->next)
+ if (a->typ == Node::chr && ch == a->sym) return a;
+ else if (a->typ == Node::clas) {
+ CharSet *s = tab->CharClassSet(a->sym);
+ if (s->Get(ch)) return a;
+ }
+ return NULL;
+}
+
+
+void DFA::GetTargetStates(Action *a, BitArray* &targets, Symbol* &endOf, bool &ctx) {
+ // compute the set of target states
+ targets = new BitArray(maxStates); endOf = NULL;
+ ctx = false;
+ for (Target *t = a->target; t != NULL; t = t->next) {
+ int stateNr = t->state->nr;
+ if (stateNr <= lastSimState) { targets->Set(stateNr, true); }
+ else { targets->Or(MeltedSet(stateNr)); }
+ if (t->state->endOf != NULL) {
+ if (endOf == NULL || endOf == t->state->endOf) {
+ endOf = t->state->endOf;
+ }
+ else {
+ wprintf(L"Tokens %ls and %ls cannot be distinguished\n", endOf->name, t->state->endOf->name);
+ errors->count++;
+ }
+ }
+ if (t->state->ctx) {
+ ctx = true;
+ // The following check seems to be unnecessary. It reported an error
+ // if a symbol + context was the prefix of another symbol, e.g.
+ // s1 = "a" "b" "c".
+ // s2 = "a" CONTEXT("b").
+ // But this is ok.
+ // if (t.state.endOf != null) {
+ // Console.WriteLine("Ambiguous context clause");
+ // Errors.count++;
+ // }
+ }
+ }
+}
+
+
+//------------------------- melted states ------------------------------
+
+
+Melted* DFA::NewMelted(BitArray *set, State *state) {
+ Melted *m = new Melted(set, state);
+ m->next = firstMelted; firstMelted = m;
+ return m;
+
+}
+
+BitArray* DFA::MeltedSet(int nr) {
+ Melted *m = firstMelted;
+ while (m != NULL) {
+ if (m->state->nr == nr) return m->set; else m = m->next;
+ }
+ //Errors::Exception("-- compiler error in Melted::Set");
+ //throw new Exception("-- compiler error in Melted::Set");
+ return NULL;
+}
+
+Melted* DFA::StateWithSet(BitArray *s) {
+ for (Melted *m = firstMelted; m != NULL; m = m->next)
+ if (Sets::Equals(s, m->set)) return m;
+ return NULL;
+}
+
+
+//------------------------ comments --------------------------------
+
+wchar_t* DFA::CommentStr(Node *p) {
+ StringBuilder s = StringBuilder();
+ while (p != NULL) {
+ if (p->typ == Node::chr) {
+ s.Append((wchar_t)p->val);
+ } else if (p->typ == Node::clas) {
+ CharSet *set = tab->CharClassSet(p->val);
+ if (set->Elements() != 1) parser->SemErr(L"character set contains more than 1 character");
+ s.Append((wchar_t) set->First());
+ }
+ else parser->SemErr(L"comment delimiters may not be structured");
+ p = p->next;
+ }
+ if (s.GetLength() == 0 || s.GetLength() > 2) {
+ parser->SemErr(L"comment delimiters must be 1 or 2 characters long");
+ s = StringBuilder(L"?");
+ }
+ return s.ToString();
+}
+
+
+void DFA::NewComment(Node *from, Node *to, bool nested) {
+ Comment *c = new Comment(CommentStr(from), CommentStr(to), nested);
+ c->next = firstComment; firstComment = c;
+}
+
+
+//------------------------ scanner generation ----------------------
+
+void DFA::GenComBody(Comment *com) {
+ fwprintf(gen, L"\t\tfor(;;) {\n");
+
+ wchar_t* res = ChCond(com->stop[0]);
+ fwprintf(gen, L"\t\t\tif (%ls) ", res);
+ fwprintf(gen, L"{\n");
+ delete [] res;
+
+ if (coco_string_length(com->stop) == 1) {
+ fwprintf(gen, L"\t\t\t\tlevel--;\n");
+ fwprintf(gen, L"\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\n");
+ fwprintf(gen, L"\t\t\t\tNextCh();\n");
+ } else {
+ fwprintf(gen, L"\t\t\t\tNextCh();\n");
+ wchar_t* res = ChCond(com->stop[1]);
+ fwprintf(gen, L"\t\t\t\tif (%ls) {\n", res);
+ delete [] res;
+ fwprintf(gen, L"\t\t\t\t\tlevel--;\n");
+ fwprintf(gen, L"\t\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\n");
+ fwprintf(gen, L"\t\t\t\t\tNextCh();\n");
+ fwprintf(gen, L"\t\t\t\t}\n");
+ }
+ if (com->nested) {
+ fwprintf(gen, L"\t\t\t}");
+ wchar_t* res = ChCond(com->start[0]);
+ fwprintf(gen, L" else if (%ls) ", res);
+ delete [] res;
+ fwprintf(gen, L"{\n");
+ if (coco_string_length(com->stop) == 1)
+ fwprintf(gen, L"\t\t\t\tlevel++; NextCh();\n");
+ else {
+ fwprintf(gen, L"\t\t\t\tNextCh();\n");
+ wchar_t* res = ChCond(com->start[1]);
+ fwprintf(gen, L"\t\t\t\tif (%ls) ", res);
+ delete [] res;
+ fwprintf(gen, L"{\n");
+ fwprintf(gen, L"\t\t\t\t\tlevel++; NextCh();\n");
+ fwprintf(gen, L"\t\t\t\t}\n");
+ }
+ }
+ fwprintf(gen, L"\t\t\t} else if (ch == buffer->EoF) return false;\n");
+ fwprintf(gen, L"\t\t\telse NextCh();\n");
+ fwprintf(gen, L"\t\t}\n");
+}
+
+void DFA::GenCommentHeader(Comment *com, int i) {
+ fwprintf(gen, L"\tbool Comment%d();\n", i);
+}
+
+void DFA::GenComment(Comment *com, int i) {
+ fwprintf(gen, L"\n");
+ fwprintf(gen, L"bool Scanner::Comment%d() ", i);
+ fwprintf(gen, L"{\n");
+ fwprintf(gen, L"\tint level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;\n");
+ if (coco_string_length(com->start) == 1) {
+ fwprintf(gen, L"\tNextCh();\n");
+ GenComBody(com);
+ } else {
+ fwprintf(gen, L"\tNextCh();\n");
+ wchar_t* res = ChCond(com->start[1]);
+ fwprintf(gen, L"\tif (%ls) ", res);
+ delete [] res;
+ fwprintf(gen, L"{\n");
+
+ fwprintf(gen, L"\t\tNextCh();\n");
+ GenComBody(com);
+
+ fwprintf(gen, L"\t} else {\n");
+ fwprintf(gen, L"\t\tbuffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0;\n");
+ fwprintf(gen, L"\t}\n");
+ fwprintf(gen, L"\treturn false;\n");
+ }
+ fwprintf(gen, L"}\n");
+}
+
+wchar_t* DFA::SymName(Symbol *sym) { // real name value is stored in Tab.literals
+ if (('a'<=sym->name[0] && sym->name[0]<='z') ||
+ ('A'<=sym->name[0] && sym->name[0]<='Z')) { //Char::IsLetter(sym->name[0])
+
+ Iterator *iter = tab->literals->GetIterator();
+ while (iter->HasNext()) {
+ DictionaryEntry *e = iter->Next();
+ if (e->val == sym) { return e->key; }
+ }
+ }
+ return sym->name;
+}
+
+void DFA::GenLiterals () {
+ Symbol *sym;
+
+ ArrayList *ts[2];
+ ts[0] = tab->terminals;
+ ts[1] = tab->pragmas;
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < ts[i]->Count; j++) {
+ sym = (Symbol*) ((*(ts[i]))[j]);
+ if (sym->tokenKind == Symbol::litToken) {
+ wchar_t* name = coco_string_create(SymName(sym));
+ if (ignoreCase) {
+ wchar_t *oldName = name;
+ name = coco_string_create_lower(name);
+ coco_string_delete(oldName);
+ }
+ // sym.name stores literals with quotes, e.g. "\"Literal\""
+
+ fwprintf(gen, L"\tkeywords.set(L");
+ // write keyword, escape non printable characters
+ for (int k = 0; name[k] != L'\0'; k++) {
+ wchar_t c = name[k];
+ fwprintf(gen, (c >= 32 && c <= 127) ? L"%lc" : L"\\x%04x", c);
+ }
+ fwprintf(gen, L", %d);\n", sym->n);
+
+ coco_string_delete(name);
+ }
+ }
+ }
+}
+
+int DFA::GenNamespaceOpen(const wchar_t *nsName) {
+ if (nsName == NULL || coco_string_length(nsName) == 0) {
+ return 0;
+ }
+ const int len = coco_string_length(nsName);
+ int startPos = 0;
+ int nrOfNs = 0;
+ do {
+ int curLen = coco_string_indexof(nsName + startPos, COCO_CPP_NAMESPACE_SEPARATOR);
+ if (curLen == -1) { curLen = len - startPos; }
+ wchar_t *curNs = coco_string_create(nsName, startPos, curLen);
+ fwprintf(gen, L"namespace %ls {\n", curNs);
+ coco_string_delete(curNs);
+ startPos = startPos + curLen + 1;
+ if (startPos < len && nsName[startPos] == COCO_CPP_NAMESPACE_SEPARATOR) {
+ ++startPos;
+ }
+ ++nrOfNs;
+ } while (startPos < len);
+ return nrOfNs;
+}
+
+void DFA::GenNamespaceClose(int nrOfNs) {
+ for (int i = 0; i < nrOfNs; ++i) {
+ fwprintf(gen, L"} // namespace\n");
+ }
+}
+
+void DFA::CheckLabels() {
+ int i;
+ State *state;
+ Action *action;
+
+ for (i=0; i < lastStateNr+1; i++) {
+ existLabel[i] = false;
+ }
+
+ for (state = firstState->next; state != NULL; state = state->next) {
+ for (action = state->firstAction; action != NULL; action = action->next) {
+ existLabel[action->target->state->nr] = true;
+ }
+ }
+}
+
+void DFA::WriteState(State *state) {
+ Symbol *endOf = state->endOf;
+ fwprintf(gen, L"\t\tcase %d:\n", state->nr);
+ if (existLabel[state->nr])
+ fwprintf(gen, L"\t\t\tcase_%d:\n", state->nr);
+
+ if (endOf != NULL && state->firstAction != NULL) {
+ fwprintf(gen, L"\t\t\trecEnd = pos; recKind = %d;\n", endOf->n);
+ }
+ bool ctxEnd = state->ctx;
+
+ for (Action *action = state->firstAction; action != NULL; action = action->next) {
+ if (action == state->firstAction) fwprintf(gen, L"\t\t\tif (");
+ else fwprintf(gen, L"\t\t\telse if (");
+ if (action->typ == Node::chr) {
+ wchar_t* res = ChCond((wchar_t)action->sym);
+ fwprintf(gen, L"%ls", res);
+ delete [] res;
+ } else PutRange(tab->CharClassSet(action->sym));
+ fwprintf(gen, L") {");
+
+ if (action->tc == Node::contextTrans) {
+ fwprintf(gen, L"apx++; "); ctxEnd = false;
+ } else if (state->ctx)
+ fwprintf(gen, L"apx = 0; ");
+ fwprintf(gen, L"AddCh(); goto case_%d;", action->target->state->nr);
+ fwprintf(gen, L"}\n");
+ }
+ if (state->firstAction == NULL)
+ fwprintf(gen, L"\t\t\t{");
+ else
+ fwprintf(gen, L"\t\t\telse {");
+ if (ctxEnd) { // final context state: cut appendix
+ fwprintf(gen, L"\n");
+ fwprintf(gen, L"\t\t\t\ttlen -= apx;\n");
+ fwprintf(gen, L"\t\t\t\tSetScannerBehindT();");
+
+ fwprintf(gen, L"\t\t\t\tbuffer->SetPos(t->pos); NextCh(); line = t->line; col = t->col;\n");
+ fwprintf(gen, L"\t\t\t\tfor (int i = 0; i < tlen; i++) NextCh();\n");
+ fwprintf(gen, L"\t\t\t\t");
+ }
+ if (endOf == NULL) {
+ fwprintf(gen, L"goto case_0;}\n");
+ } else {
+ fwprintf(gen, L"t->kind = %d; ", endOf->n);
+ if (endOf->tokenKind == Symbol::classLitToken) {
+ if (ignoreCase) {
+ fwprintf(gen, L"wchar_t *literal = coco_string_create_lower(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;}\n");
+ } else {
+ fwprintf(gen, L"wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;}\n");
+ }
+ } else {
+ fwprintf(gen, L"break;}\n");
+ }
+ }
+}
+
+void DFA::WriteStartTab() {
+ bool firstRange = true;
+ for (Action *action = firstState->firstAction; action != NULL; action = action->next) {
+ int targetState = action->target->state->nr;
+ if (action->typ == Node::chr) {
+ fwprintf(gen, L"\tstart.set(%d, %d);\n", action->sym, targetState);
+ } else {
+ CharSet *s = tab->CharClassSet(action->sym);
+ for (CharSet::Range *r = s->head; r != NULL; r = r->next) {
+ if (firstRange) {
+ firstRange = false;
+ fwprintf(gen, L"\tint i;\n");
+ }
+ fwprintf(gen, L"\tfor (i = %d; i <= %d; ++i) start.set(i, %d);\n", r->from, r->to, targetState);
+ }
+ }
+ }
+ fwprintf(gen, L"\t\tstart.set(Buffer::EoF, -1);\n");
+}
+
+void DFA::WriteScanner() {
+ Generator g = Generator(tab, errors);
+ fram = g.OpenFrame(L"Scanner.frame");
+ gen = g.OpenGen(L"Scanner.h");
+ if (dirtyDFA) MakeDeterministic();
+
+ // Header
+ g.GenCopyright();
+ g.SkipFramePart(L"-->begin");
+
+ g.CopyFramePart(L"-->prefix");
+ g.GenPrefixFromNamespace();
+
+ g.CopyFramePart(L"-->prefix");
+ g.GenPrefixFromNamespace();
+
+ g.CopyFramePart(L"-->namespace_open");
+ int nrOfNs = GenNamespaceOpen(tab->nsName);
+
+ g.CopyFramePart(L"-->casing0");
+ if (ignoreCase) {
+ fwprintf(gen, L"\twchar_t valCh; // current input character (for token.val)\n");
+ }
+ g.CopyFramePart(L"-->commentsheader");
+ Comment *com = firstComment;
+ int cmdIdx = 0;
+ while (com != NULL) {
+ GenCommentHeader(com, cmdIdx);
+ com = com->next; cmdIdx++;
+ }
+
+ g.CopyFramePart(L"-->namespace_close");
+ GenNamespaceClose(nrOfNs);
+
+ g.CopyFramePart(L"-->implementation");
+ fclose(gen);
+
+ // Source
+ gen = g.OpenGen(L"Scanner.cpp");
+ g.GenCopyright();
+ g.SkipFramePart(L"-->begin");
+ g.CopyFramePart(L"-->namespace_open");
+ nrOfNs = GenNamespaceOpen(tab->nsName);
+
+ g.CopyFramePart(L"-->declarations");
+ fwprintf(gen, L"\tmaxT = %d;\n", tab->terminals->Count - 1);
+ fwprintf(gen, L"\tnoSym = %d;\n", tab->noSym->n);
+ WriteStartTab();
+ GenLiterals();
+
+ g.CopyFramePart(L"-->initialization");
+ g.CopyFramePart(L"-->casing1");
+ if (ignoreCase) {
+ fwprintf(gen, L"\t\tvalCh = ch;\n");
+ fwprintf(gen, L"\t\tif ('A' <= ch && ch <= 'Z') ch = ch - 'A' + 'a'; // ch.ToLower()");
+ }
+ g.CopyFramePart(L"-->casing2");
+ fwprintf(gen, L"\t\ttval[tlen++] = ");
+ if (ignoreCase) fwprintf(gen, L"valCh;"); else fwprintf(gen, L"ch;");
+
+ g.CopyFramePart(L"-->comments");
+ com = firstComment; cmdIdx = 0;
+ while (com != NULL) {
+ GenComment(com, cmdIdx);
+ com = com->next; cmdIdx++;
+ }
+
+ g.CopyFramePart(L"-->scan1");
+ fwprintf(gen, L"\t\t\t");
+ if (tab->ignored->Elements() > 0) { PutRange(tab->ignored); } else { fwprintf(gen, L"false"); }
+
+ g.CopyFramePart(L"-->scan2");
+ if (firstComment != NULL) {
+ fwprintf(gen, L"\tif (");
+ com = firstComment; cmdIdx = 0;
+ while (com != NULL) {
+ wchar_t* res = ChCond(com->start[0]);
+ fwprintf(gen, L"(%ls && Comment%d())", res, cmdIdx);
+ delete [] res;
+ if (com->next != NULL) {
+ fwprintf(gen, L" || ");
+ }
+ com = com->next; cmdIdx++;
+ }
+ fwprintf(gen, L") return NextToken();");
+ }
+ if (hasCtxMoves) { fwprintf(gen, L"\n"); fwprintf(gen, L"\tint apx = 0;"); } /* pdt */
+ g.CopyFramePart(L"-->scan3");
+
+ /* CSB 02-10-05 check the Labels */
+ existLabel = new bool[lastStateNr+1];
+ CheckLabels();
+ for (State *state = firstState->next; state != NULL; state = state->next)
+ WriteState(state);
+ delete [] existLabel;
+
+ g.CopyFramePart(L"-->namespace_close");
+ GenNamespaceClose(nrOfNs);
+
+ g.CopyFramePart(NULL);
+ fclose(gen);
+}
+
+DFA::DFA(Parser *parser) {
+ this->parser = parser;
+ tab = parser->tab;
+ errors = parser->errors;
+ trace = parser->trace;
+ firstState = NULL; lastState = NULL; lastStateNr = -1;
+ firstState = NewState();
+ firstMelted = NULL; firstComment = NULL;
+ ignoreCase = false;
+ dirtyDFA = false;
+ hasCtxMoves = false;
+}
+
+}; // namespace
diff --git a/old/cococpp/DFA.h b/old/cococpp/DFA.h
new file mode 100644
index 0000000..57ed846
--- /dev/null
+++ b/old/cococpp/DFA.h
@@ -0,0 +1,132 @@
+/*-------------------------------------------------------------------------
+DFA -- Generation of the Scanner Automaton
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_DFA_H__)
+#define COCO_DFA_H__
+
+#include <stddef.h>
+#include "Action.h"
+#include "Comment.h"
+#include "State.h"
+#include "Symbol.h"
+#include "Melted.h"
+#include "Node.h"
+#include "Target.h"
+
+namespace Coco {
+
+
+class Parser;
+class Tab;
+class BitArray;
+
+class DFA
+{
+public:
+ int maxStates;
+ int lastStateNr; // highest state number
+ State *firstState;
+ State *lastState; // last allocated state
+ int lastSimState; // last non melted state
+ FILE* fram; // scanner frame input
+ FILE* gen; // generated scanner file
+ Symbol *curSy; // current token to be recognized (in FindTrans)
+ Node *curGraph; // start of graph for current token (in FindTrans)
+ bool ignoreCase; // true if input should be treated case-insensitively
+ bool dirtyDFA; // DFA may become nondeterministic in MatchLiteral
+ bool hasCtxMoves; // DFA has context transitions
+ bool *existLabel; // checking the Labels (in order to avoid the warning messages)
+
+ Parser *parser; // other Coco objects
+ Tab *tab;
+ Errors *errors;
+ FILE* trace;
+
+ Melted *firstMelted; // head of melted state list
+ Comment *firstComment; // list of comments
+
+ //---------- Output primitives
+ wchar_t* Ch(wchar_t ch);
+ wchar_t* ChCond(wchar_t ch);
+ void PutRange(CharSet *s);
+
+ //---------- State handling
+ State* NewState();
+ void NewTransition(State *from, State *to, int typ, int sym, int tc);
+ void CombineShifts();
+ void FindUsedStates(State *state, BitArray *used);
+ void DeleteRedundantStates();
+ State* TheState(Node *p);
+ void Step(State *from, Node *p, BitArray *stepped);
+ void NumberNodes(Node *p, State *state, bool renumIter);
+ void FindTrans (Node *p, bool start, BitArray *marked);
+ void ConvertToStates(Node *p, Symbol *sym);
+ // match string against current automaton; store it either as a fixedToken or as a litToken
+ void MatchLiteral(wchar_t* s, Symbol *sym);
+ void SplitActions(State *state, Action *a, Action *b);
+ bool Overlap(Action *a, Action *b);
+ bool MakeUnique(State *state); // return true if actions were split
+ void MeltStates(State *state);
+ void FindCtxStates();
+ void MakeDeterministic();
+ void PrintStates();
+ void CheckLabels();
+
+ //---------------------------- actions --------------------------------
+ Action* FindAction(State *state, wchar_t ch);
+ void GetTargetStates(Action *a, BitArray* &targets, Symbol* &endOf, bool &ctx);
+
+ //------------------------- melted states ------------------------------
+ Melted* NewMelted(BitArray *set, State *state);
+ BitArray* MeltedSet(int nr);
+ Melted* StateWithSet(BitArray *s);
+
+ //------------------------ comments --------------------------------
+ wchar_t* CommentStr(Node *p);
+ void NewComment(Node *from, Node *to, bool nested);
+
+ //------------------------ scanner generation ----------------------
+ void GenComBody(Comment *com);
+ void GenCommentHeader(Comment *com, int i);
+ void GenComment(Comment *com, int i);
+ void CopyFramePart(const wchar_t* stop);
+ wchar_t* SymName(Symbol *sym); // real name value is stored in Tab.literals
+ void GenLiterals ();
+ int GenNamespaceOpen(const wchar_t* nsName);
+ void GenNamespaceClose(int nrOfNs);
+ void WriteState(State *state);
+ void WriteStartTab();
+ void OpenGen(const wchar_t* genName, bool backUp); /* pdt */
+ void WriteScanner();
+ DFA(Parser *parser);
+};
+
+}; // namespace
+
+#endif // !defined(COCO_DFA_H__)
diff --git a/old/cococpp/Generator.cpp b/old/cococpp/Generator.cpp
new file mode 100644
index 0000000..d9c670b
--- /dev/null
+++ b/old/cococpp/Generator.cpp
@@ -0,0 +1,182 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+#include "Generator.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+ Generator::Generator(Tab *tab, Errors *errors) {
+ this->errors = errors;
+ this->tab = tab;
+ fram = NULL;
+ gen = NULL;
+ frameFile = NULL;
+ }
+
+ FILE* Generator::OpenFrame(const wchar_t* frame) {
+ if (coco_string_length(tab->frameDir) != 0) {
+ frameFile = coco_string_create_append(tab->frameDir, L"/");
+ coco_string_merge(frameFile, frame);
+ char *chFrameFile = coco_string_create_char(frameFile);
+ fram = fopen(chFrameFile, "r");
+ delete [] chFrameFile;
+ }
+ if (fram == NULL) {
+ delete [] frameFile;
+ frameFile = coco_string_create_append(tab->srcDir, frame); /* pdt */
+ char *chFrameFile = coco_string_create_char(frameFile);
+ fram = fopen(chFrameFile, "r");
+ delete [] chFrameFile;
+ }
+ if (fram == NULL) {
+ wchar_t *message = coco_string_create_append(L"-- Cannot find : ", frame);
+ errors->Exception(message);
+ delete [] message;
+ }
+
+ return fram;
+ }
+
+
+ FILE* Generator::OpenGen(const wchar_t *genName) { /* pdt */
+ wchar_t *fn = coco_string_create_append(tab->outDir, genName); /* pdt */
+ char *chFn = coco_string_create_char(fn);
+
+ if ((gen = fopen(chFn, "r")) != NULL) {
+ fclose(gen);
+ wchar_t *oldName = coco_string_create_append(fn, L".old");
+ char *chOldName = coco_string_create_char(oldName);
+ remove(chOldName); rename(chFn, chOldName); // copy with overwrite
+ coco_string_delete(chOldName);
+ coco_string_delete(oldName);
+ }
+ if ((gen = fopen(chFn, "w")) == NULL) {
+ wchar_t *message = coco_string_create_append(L"-- Cannot generate : ", genName);
+ errors->Exception(message);
+ delete [] message;
+ }
+ coco_string_delete(chFn);
+ coco_string_delete(fn);
+
+ return gen;
+ }
+
+
+ void Generator::GenCopyright() {
+ FILE *file = NULL;
+
+ if (coco_string_length(tab->frameDir) != 0) {
+ wchar_t *copyFr = coco_string_create_append(tab->frameDir, L"/Copyright.frame");
+ char *chCopyFr = coco_string_create_char(copyFr);
+ file = fopen(chCopyFr, "r");
+ delete [] copyFr;
+ delete [] chCopyFr;
+ }
+ if (file == NULL) {
+ wchar_t *copyFr = coco_string_create_append(tab->srcDir, L"Copyright.frame");
+ char *chCopyFr = coco_string_create_char(copyFr);
+ file = fopen(chCopyFr, "r");
+ delete [] copyFr;
+ delete [] chCopyFr;
+ }
+ if (file == NULL) {
+ return;
+ }
+
+ FILE *scannerFram = fram;
+ fram = file;
+
+ CopyFramePart(NULL);
+ fram = scannerFram;
+
+ fclose(file);
+ }
+
+ void Generator::GenPrefixFromNamespace() {
+ const wchar_t *nsName = tab->nsName;
+ if (nsName == NULL || coco_string_length(nsName) == 0) {
+ return;
+ }
+ const int len = coco_string_length(nsName);
+ int startPos = 0;
+ do {
+ int curLen = coco_string_indexof(nsName + startPos, COCO_CPP_NAMESPACE_SEPARATOR);
+ if (curLen == -1) { curLen = len - startPos; }
+ wchar_t *curNs = coco_string_create(nsName, startPos, curLen);
+ fwprintf(gen, L"%ls_", curNs);
+ coco_string_delete(curNs);
+ startPos = startPos + curLen + 1;
+ } while (startPos < len);
+ }
+
+ void Generator::SkipFramePart(const wchar_t *stop) {
+ CopyFramePart(stop, false);
+ }
+
+ void Generator::CopyFramePart(const wchar_t *stop) {
+ CopyFramePart(stop, true);
+ }
+
+ void Generator::CopyFramePart(const wchar_t* stop, bool generateOutput) {
+ wchar_t startCh = 0;
+ int endOfStopString = 0;
+ wchar_t ch = 0;
+
+ if (stop != NULL) {
+ startCh = stop[0];
+ endOfStopString = coco_string_length(stop)-1;
+ }
+
+ fwscanf(fram, L"%lc", &ch); // fram.ReadByte();
+ while (!feof(fram)) { // ch != EOF
+ if (stop != NULL && ch == startCh) {
+ int i = 0;
+ do {
+ if (i == endOfStopString) return; // stop[0..i] found
+ fwscanf(fram, L"%lc", &ch); i++;
+ } while (ch == stop[i]);
+ // stop[0..i-1] found; continue with last read character
+ if (generateOutput) {
+ wchar_t *subStop = coco_string_create(stop, 0, i);
+ fwprintf(gen, L"%ls", subStop);
+ coco_string_delete(subStop);
+ }
+ } else {
+ if (generateOutput) { fwprintf(gen, L"%lc", ch); }
+ fwscanf(fram, L"%lc", &ch);
+ }
+ }
+ if (stop != NULL) {
+ wchar_t *message = coco_string_create_append(L" -- Incomplete or corrupt frame file: ", frameFile);
+ errors->Exception(message);
+ delete [] message;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/old/cococpp/Generator.h b/old/cococpp/Generator.h
new file mode 100644
index 0000000..eba64dd
--- /dev/null
+++ b/old/cococpp/Generator.h
@@ -0,0 +1,61 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+#if !defined(COCO_GENERATOR_H__)
+#define COCO_GENERATOR_H__
+
+#include <stdio.h>
+#include "Tab.h"
+#include "Parser.h"
+
+namespace Coco {
+
+class Generator {
+public:
+ Generator(Tab *tab, Errors *errors);
+ FILE* OpenFrame(const wchar_t* frame);
+ FILE* OpenGen(const wchar_t *genName);
+ void GenCopyright();
+ void GenPrefixFromNamespace();
+ void SkipFramePart(const wchar_t *stop);
+ void CopyFramePart(const wchar_t *stop);
+
+private:
+ FILE* fram;
+ FILE* gen;
+ Tab *tab;
+ wchar_t* frameFile;
+ Errors *errors;
+
+ void CopyFramePart(const wchar_t* stop, bool generateOutput);
+
+};
+
+} // namespace
+
+#endif // !defined(COCO_GENERATOR_H__)
diff --git a/old/cococpp/Graph.h b/old/cococpp/Graph.h
new file mode 100644
index 0000000..4f0018c
--- /dev/null
+++ b/old/cococpp/Graph.h
@@ -0,0 +1,59 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_GRAPH_H__)
+#define COCO_GRAPH_H__
+
+#include "Node.h"
+
+namespace Coco {
+
+class Graph {
+public:
+ Node *l; // left end of graph = head
+ Node *r; // right end of graph = list of nodes to be linked to successor graph
+
+ Graph() {
+ l = NULL; r = NULL;
+ }
+
+ Graph(Node *left, Node *right) {
+ l = left; r = right;
+ }
+
+ Graph(Node *p) {
+ l = p; r = p;
+ }
+
+ virtual ~Graph() {
+ }
+};
+
+}; // namespace
+
+#endif // !defined(COCO_GRAPH_H__)
diff --git a/old/cococpp/HashTable.cpp b/old/cococpp/HashTable.cpp
new file mode 100644
index 0000000..da0a92a
--- /dev/null
+++ b/old/cococpp/HashTable.cpp
@@ -0,0 +1,115 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <memory.h>
+#include <stdio.h>
+#include "HashTable.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+HashTable::HashTable(int size) {
+ this->size = size;
+ data = new Obj*[size];
+ memset(data, 0, size * sizeof(Obj*));
+}
+
+HashTable::~HashTable() {
+ for (int i = 0; i < size; ++i) {
+ Obj *o = data[i];
+ while (o != NULL) {
+ Obj *del = o;
+ o = o->next;
+ delete del;
+ }
+ }
+ delete[] data;
+ data = NULL;
+};
+
+HashTable::Obj* HashTable::Get0(wchar_t *key) const {
+ int k = coco_string_hash(key) % size;
+ HashTable::Obj *o = data[k];
+ while (o != NULL && !coco_string_equal(key, o->key)) {
+ o = o->next;
+ }
+ return o;
+}
+
+void HashTable::Set(wchar_t *key, void *val) {
+ HashTable::Obj *o = Get0(key);
+ if (o == NULL) {
+ // new entry
+ int k = coco_string_hash(key) % size;
+ o = new Obj();
+ o->key = key;
+ o->val = val;
+ o->next = data[k];
+ data[k] = o;
+ } else {
+ // exist entry - overwrite
+ o->val = val;
+ }
+}
+
+void* HashTable::Get(wchar_t *key) const {
+ HashTable::Obj *o = Get0(key);
+ if (o != NULL) {
+ return o->val;
+ }
+ return NULL;
+}
+
+Iterator* HashTable::GetIterator() {
+ return new HashTable::Iter(this);
+}
+
+HashTable::Iter::Iter(HashTable *ht) {
+ this->ht = ht;
+ this->pos = 0;
+ this->cur = NULL;
+}
+
+bool HashTable::Iter::HasNext() {
+ while (cur == NULL && pos < ht->size) {
+ cur = ht->data[pos];
+ ++pos;
+ }
+ return cur != NULL;
+}
+
+DictionaryEntry* HashTable::Iter::Next() {
+ if (!HasNext()) {
+ return NULL;
+ }
+ Obj *next = cur;
+ cur = cur->next;
+ return next;
+}
+
+}; // namespace
diff --git a/old/cococpp/HashTable.h b/old/cococpp/HashTable.h
new file mode 100644
index 0000000..487f1b9
--- /dev/null
+++ b/old/cococpp/HashTable.h
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_HASHTABLE_H__)
+#define COCO_HASHTABLE_H__
+
+#include <wchar.h>
+
+namespace Coco {
+
+class DictionaryEntry {
+public:
+ wchar_t *key;
+ void *val;
+};
+
+class Iterator {
+public:
+ virtual bool HasNext() = 0;
+ virtual DictionaryEntry* Next() = 0;
+};
+
+class HashTable
+{
+public:
+ HashTable(int size = 128);
+ virtual ~HashTable();
+
+ virtual void Set(wchar_t *key, void *value);
+ virtual void* Get(wchar_t *key) const;
+ inline void* operator[](wchar_t *key) const { return Get(key); };
+ virtual Iterator* GetIterator();
+
+private:
+ class Obj : public DictionaryEntry {
+ public:
+ Obj *next;
+ };
+
+ class Iter : public Iterator {
+ private:
+ HashTable *ht;
+ int pos;
+ Obj* cur;
+
+ public:
+ Iter(HashTable *ht);
+ virtual bool HasNext();
+ virtual DictionaryEntry* Next();
+ };
+
+ Obj* Get0(wchar_t *key) const;
+ Obj **data;
+ int size;
+};
+
+}; // namespace
+
+#endif // !defined(COCO_HASHTABLE_H__)
diff --git a/old/cococpp/Makefile b/old/cococpp/Makefile
new file mode 100644
index 0000000..b6fe18e
--- /dev/null
+++ b/old/cococpp/Makefile
@@ -0,0 +1,11 @@
+all:
+ g++ *.cpp -o Coco $(CFLAGS)
+
+clean:
+ rm -f Coco
+
+install:
+ ln -s /usr/lib/coco-cpp/Coco $(DESTDIR)/usr/bin/cococpp
+ install -m 0755 Coco $(DESTDIR)/usr/lib/coco-cpp
+ install -m 0644 *frame $(DESTDIR)/usr/share/coco-cpp
+
diff --git a/old/cococpp/Melted.cpp b/old/cococpp/Melted.cpp
new file mode 100644
index 0000000..f63c9f0
--- /dev/null
+++ b/old/cococpp/Melted.cpp
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Melted.h"
+
+namespace Coco {
+
+class BitArray;
+
+Melted::Melted(BitArray *set, State *state) {
+ this->set = set; this->state = state;
+}
+
+}; // namespace
diff --git a/old/cococpp/Melted.h b/old/cococpp/Melted.h
new file mode 100644
index 0000000..960faa2
--- /dev/null
+++ b/old/cococpp/Melted.h
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_MELTED_H__)
+#define COCO_MELTED_H__
+
+#include "State.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+class BitArray;
+
+class Melted // info about melted states
+{
+public:
+ BitArray *set; // set of old states
+ State *state; // new state
+ Melted *next;
+
+ Melted(BitArray *set, State *state);
+};
+
+}; // namespace
+
+#endif // !defined(COCO_MELTED_H__)
diff --git a/old/cococpp/Node.cpp b/old/cococpp/Node.cpp
new file mode 100644
index 0000000..4fd8adb
--- /dev/null
+++ b/old/cococpp/Node.cpp
@@ -0,0 +1,69 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Node.h"
+
+namespace Coco {
+
+// constants for node kinds
+int Node::t = 1; // terminal symbol
+int Node::pr = 2; // pragma
+int Node::nt = 3; // nonterminal symbol
+int Node::clas = 4; // character class
+int Node::chr = 5; // character
+int Node::wt = 6; // weak terminal symbol
+int Node::any = 7; //
+int Node::eps = 8; // empty
+int Node::sync = 9; // synchronization symbol
+int Node::sem = 10; // semantic action: (. .)
+int Node::alt = 11; // alternative: |
+int Node::iter = 12; // iteration: { }
+int Node::opt = 13; // option: [ ]
+int Node::rslv = 14; // resolver expr
+
+int Node::normalTrans = 0; // transition codes
+int Node::contextTrans = 1;
+
+
+Node::Node(int typ, Symbol *sym, int line) {
+ this->n = 0;
+ this->next = NULL;
+ this->down = NULL;
+ this->sub = NULL;
+ this->up = false;
+ this->val = 0;
+ this->code = 0;
+ this->set = NULL;
+ this->pos = NULL;
+ this->state = NULL;
+ this->state = 0;
+
+ this->typ = typ; this->sym = sym; this->line = line;
+}
+
+}; // namespace
diff --git a/old/cococpp/Node.h b/old/cococpp/Node.h
new file mode 100644
index 0000000..882da38
--- /dev/null
+++ b/old/cococpp/Node.h
@@ -0,0 +1,86 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_NODE_H__)
+#define COCO_NODE_H__
+
+#include <stdio.h>
+#include "Position.h"
+#include "State.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+class Symbol;
+class BitArray;
+
+class Node {
+public:
+ // constants for node kinds
+ static int t; // terminal symbol
+ static int pr; // pragma
+ static int nt; // nonterminal symbol
+ static int clas; // character class
+ static int chr; // character
+ static int wt; // weak terminal symbol
+ static int any; //
+ static int eps; // empty
+ static int sync; // synchronization symbol
+ static int sem; // semantic action: (. .)
+ static int alt; // alternative: |
+ static int iter; // iteration: { }
+ static int opt; // option: [ ]
+ static int rslv; // resolver expr
+
+ static int normalTrans; // transition codes
+ static int contextTrans;
+
+ int n; // node number
+ int typ; // t, nt, wt, chr, clas, any, eps, sem, sync, alt, iter, opt, rslv
+ Node *next; // to successor node
+ Node *down; // alt: to next alternative
+ Node *sub; // alt, iter, opt: to first node of substructure
+ bool up; // true: "next" leads to successor in enclosing structure
+ Symbol *sym; // nt, t, wt: symbol represented by this node
+ int val; // chr: ordinal character value
+ // clas: index of character class
+ int code; // chr, clas: transition code
+ BitArray *set; // any, sync: the set represented by this node
+ Position *pos; // nt, t, wt: pos of actual attributes
+ // sem: pos of semantic action in source text
+ // rslv: pos of resolver in source text
+ int line; // source text line number of item in this node
+ State *state; // DFA state corresponding to this node
+ // (only used in DFA.ConvertToStates)
+
+ Node(int typ, Symbol *sym, int line);
+};
+
+}; // namespace
+
+#endif // !defined(COCO_NODE_H__)
diff --git a/old/cococpp/Parser.cpp b/old/cococpp/Parser.cpp
new file mode 100644
index 0000000..6c6f893
--- /dev/null
+++ b/old/cococpp/Parser.cpp
@@ -0,0 +1,925 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+namespace Coco {
+
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+ if (la->kind == _ddtSym) {
+ tab->SetDDT(la->val);
+ }
+ if (la->kind == _optionSym) {
+ tab->SetOption(la->val);
+ }
+
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+void Parser::Coco() {
+ Symbol *sym; Graph *g, *g1, *g2; wchar_t* gramName = NULL; CharSet *s;
+ int beg = la->pos; int line = la->line;
+ while (StartOf(1)) {
+ Get();
+ }
+ if (la->pos != beg) {
+ pgen->usingPos = new Position(beg, t->pos + coco_string_length(t->val), 0, line);
+ }
+
+ Expect(6 /* "COMPILER" */);
+ genScanner = true;
+ tab->ignored = new CharSet();
+ Expect(_ident);
+ gramName = coco_string_create(t->val);
+ beg = la->pos;
+ line = la->line;
+
+ while (StartOf(2)) {
+ Get();
+ }
+ tab->semDeclPos = new Position(beg, la->pos, 0, line);
+ if (la->kind == 7 /* "IGNORECASE" */) {
+ Get();
+ dfa->ignoreCase = true;
+ }
+ if (la->kind == 8 /* "CHARACTERS" */) {
+ Get();
+ while (la->kind == _ident) {
+ SetDecl();
+ }
+ }
+ if (la->kind == 9 /* "TOKENS" */) {
+ Get();
+ while (la->kind == _ident || la->kind == _string || la->kind == _char) {
+ TokenDecl(Node::t);
+ }
+ }
+ if (la->kind == 10 /* "PRAGMAS" */) {
+ Get();
+ while (la->kind == _ident || la->kind == _string || la->kind == _char) {
+ TokenDecl(Node::pr);
+ }
+ }
+ while (la->kind == 11 /* "COMMENTS" */) {
+ Get();
+ bool nested = false;
+ Expect(12 /* "FROM" */);
+ TokenExpr(g1);
+ Expect(13 /* "TO" */);
+ TokenExpr(g2);
+ if (la->kind == 14 /* "NESTED" */) {
+ Get();
+ nested = true;
+ }
+ dfa->NewComment(g1->l, g2->l, nested);
+ }
+ while (la->kind == 15 /* "IGNORE" */) {
+ Get();
+ Set(s);
+ tab->ignored->Or(s);
+ }
+ while (!(la->kind == _EOF || la->kind == 16 /* "PRODUCTIONS" */)) {SynErr(42); Get();}
+ Expect(16 /* "PRODUCTIONS" */);
+ if (genScanner) dfa->MakeDeterministic();
+ tab->DeleteNodes();
+
+ while (la->kind == _ident) {
+ Get();
+ sym = tab->FindSym(t->val);
+ bool undef = (sym == NULL);
+ if (undef) sym = tab->NewSym(Node::nt, t->val, t->line);
+ else {
+ if (sym->typ == Node::nt) {
+ if (sym->graph != NULL) SemErr(L"name declared twice");
+ } else SemErr(L"this symbol kind not allowed on left side of production");
+ sym->line = t->line;
+ }
+ bool noAttrs = (sym->attrPos == NULL);
+ sym->attrPos = NULL;
+
+ if (la->kind == 24 /* "<" */ || la->kind == 26 /* "<." */) {
+ AttrDecl(sym);
+ }
+ if (!undef)
+ if (noAttrs != (sym->attrPos == NULL))
+ SemErr(L"attribute mismatch between declaration and use of this symbol");
+
+ if (la->kind == 39 /* "(." */) {
+ SemText(sym->semPos);
+ }
+ ExpectWeak(17 /* "=" */, 3);
+ Expression(g);
+ sym->graph = g->l;
+ tab->Finish(g);
+
+ ExpectWeak(18 /* "." */, 4);
+ }
+ Expect(19 /* "END" */);
+ Expect(_ident);
+ if (!coco_string_equal(gramName, t->val))
+ SemErr(L"name does not match grammar name");
+ tab->gramSy = tab->FindSym(gramName);
+ if (tab->gramSy == NULL)
+ SemErr(L"missing production for grammar name");
+ else {
+ sym = tab->gramSy;
+ if (sym->attrPos != NULL)
+ SemErr(L"grammar symbol must not have attributes");
+ }
+ tab->noSym = tab->NewSym(Node::t, L"???", 0); // noSym gets highest number
+ tab->SetupAnys();
+ tab->RenumberPragmas();
+ if (tab->ddt[2]) tab->PrintNodes();
+ if (errors->count == 0) {
+ wprintf(L"checking\n");
+ tab->CompSymbolSets();
+ if (tab->ddt[7]) tab->XRef();
+ if (tab->GrammarOk()) {
+ wprintf(L"parser");
+ pgen->WriteParser();
+ if (genScanner) {
+ wprintf(L" + scanner");
+ dfa->WriteScanner();
+ if (tab->ddt[0]) dfa->PrintStates();
+ }
+ wprintf(L" generated\n");
+ if (tab->ddt[8]) pgen->WriteStatistics();
+ }
+ }
+ if (tab->ddt[6]) tab->PrintSymbolTable();
+
+ Expect(18 /* "." */);
+}
+
+void Parser::SetDecl() {
+ CharSet *s;
+ Expect(_ident);
+ wchar_t *name = coco_string_create(t->val);
+ CharClass *c = tab->FindCharClass(name);
+ if (c != NULL) SemErr(L"name declared twice");
+
+ Expect(17 /* "=" */);
+ Set(s);
+ if (s->Elements() == 0) SemErr(L"character set must not be empty");
+ tab->NewCharClass(name, s);
+
+ Expect(18 /* "." */);
+}
+
+void Parser::TokenDecl(int typ) {
+ wchar_t* name = NULL; int kind; Symbol *sym; Graph *g;
+ Sym(name, kind);
+ sym = tab->FindSym(name);
+ if (sym != NULL) SemErr(L"name declared twice");
+ else {
+ sym = tab->NewSym(typ, name, t->line);
+ sym->tokenKind = Symbol::fixedToken;
+ }
+ tokenString = NULL;
+
+ while (!(StartOf(5))) {SynErr(43); Get();}
+ if (la->kind == 17 /* "=" */) {
+ Get();
+ TokenExpr(g);
+ Expect(18 /* "." */);
+ if (kind == str) SemErr(L"a literal must not be declared with a structure");
+ tab->Finish(g);
+ if (tokenString == NULL || coco_string_equal(tokenString, noString))
+ dfa->ConvertToStates(g->l, sym);
+ else { // TokenExpr is a single string
+ if ((*(tab->literals))[tokenString] != NULL)
+ SemErr(L"token string declared twice");
+ tab->literals->Set(tokenString, sym);
+ dfa->MatchLiteral(tokenString, sym);
+ }
+
+ } else if (StartOf(6)) {
+ if (kind == id) genScanner = false;
+ else dfa->MatchLiteral(sym->name, sym);
+
+ } else SynErr(44);
+ if (la->kind == 39 /* "(." */) {
+ SemText(sym->semPos);
+ if (typ != Node::pr) SemErr(L"semantic action not allowed here");
+ }
+}
+
+void Parser::TokenExpr(Graph* &g) {
+ Graph *g2;
+ TokenTerm(g);
+ bool first = true;
+ while (WeakSeparator(28 /* "|" */,8,7) ) {
+ TokenTerm(g2);
+ if (first) { tab->MakeFirstAlt(g); first = false; }
+ tab->MakeAlternative(g, g2);
+
+ }
+}
+
+void Parser::Set(CharSet* &s) {
+ CharSet *s2;
+ SimSet(s);
+ while (la->kind == 20 /* "+" */ || la->kind == 21 /* "-" */) {
+ if (la->kind == 20 /* "+" */) {
+ Get();
+ SimSet(s2);
+ s->Or(s2);
+ } else {
+ Get();
+ SimSet(s2);
+ s->Subtract(s2);
+ }
+ }
+}
+
+void Parser::AttrDecl(Symbol *sym) {
+ if (la->kind == 24 /* "<" */) {
+ Get();
+ int beg = la->pos; int col = la->col; int line = la->line;
+ while (StartOf(9)) {
+ if (StartOf(10)) {
+ Get();
+ } else {
+ Get();
+ SemErr(L"bad string in attributes");
+ }
+ }
+ Expect(25 /* ">" */);
+ if (t->pos > beg)
+ sym->attrPos = new Position(beg, t->pos, col, line);
+ } else if (la->kind == 26 /* "<." */) {
+ Get();
+ int beg = la->pos; int col = la->col; int line = la->line;
+ while (StartOf(11)) {
+ if (StartOf(12)) {
+ Get();
+ } else {
+ Get();
+ SemErr(L"bad string in attributes");
+ }
+ }
+ Expect(27 /* ".>" */);
+ if (t->pos > beg)
+ sym->attrPos = new Position(beg, t->pos, col, line);
+ } else SynErr(45);
+}
+
+void Parser::SemText(Position* &pos) {
+ Expect(39 /* "(." */);
+ int beg = la->pos; int col = la->col; int line = t->line;
+ while (StartOf(13)) {
+ if (StartOf(14)) {
+ Get();
+ } else if (la->kind == _badString) {
+ Get();
+ SemErr(L"bad string in semantic action");
+ } else {
+ Get();
+ SemErr(L"missing end of previous semantic action");
+ }
+ }
+ Expect(40 /* ".)" */);
+ pos = new Position(beg, t->pos, col, line);
+}
+
+void Parser::Expression(Graph* &g) {
+ Graph *g2;
+ Term(g);
+ bool first = true;
+ while (WeakSeparator(28 /* "|" */,16,15) ) {
+ Term(g2);
+ if (first) { tab->MakeFirstAlt(g); first = false; }
+ tab->MakeAlternative(g, g2);
+
+ }
+}
+
+void Parser::SimSet(CharSet* &s) {
+ int n1, n2;
+ s = new CharSet();
+ if (la->kind == _ident) {
+ Get();
+ CharClass *c = tab->FindCharClass(t->val);
+ if (c == NULL) SemErr(L"undefined name"); else s->Or(c->set);
+
+ } else if (la->kind == _string) {
+ Get();
+ wchar_t *subName2 = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ wchar_t *name = tab->Unescape(subName2);
+ coco_string_delete(subName2);
+ wchar_t ch;
+ int len = coco_string_length(name);
+ for(int i=0; i < len; i++) {
+ ch = name[i];
+ if (dfa->ignoreCase) {
+ if ((L'A' <= ch) && (ch <= L'Z')) ch = ch - (L'A' - L'a'); // ch.ToLower()
+ }
+ s->Set(ch);
+ }
+ coco_string_delete(name);
+
+ } else if (la->kind == _char) {
+ Char(n1);
+ s->Set(n1);
+ if (la->kind == 22 /* ".." */) {
+ Get();
+ Char(n2);
+ for (int i = n1; i <= n2; i++) s->Set(i);
+ }
+ } else if (la->kind == 23 /* "ANY" */) {
+ Get();
+ s = new CharSet(); s->Fill();
+ } else SynErr(46);
+}
+
+void Parser::Char(int &n) {
+ Expect(_char);
+ n = 0;
+ wchar_t* subName = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ wchar_t* name = tab->Unescape(subName);
+ coco_string_delete(subName);
+
+ // "<= 1" instead of "== 1" to allow the escape sequence '\0' in c++
+ if (coco_string_length(name) <= 1) n = name[0];
+ else SemErr(L"unacceptable character value");
+ coco_string_delete(name);
+ if (dfa->ignoreCase && (((wchar_t) n) >= 'A') && (((wchar_t) n) <= 'Z')) n += 32;
+
+}
+
+void Parser::Sym(wchar_t* &name, int &kind) {
+ name = coco_string_create(L"???"); kind = id;
+ if (la->kind == _ident) {
+ Get();
+ kind = id; coco_string_delete(name); name = coco_string_create(t->val);
+ } else if (la->kind == _string || la->kind == _char) {
+ if (la->kind == _string) {
+ Get();
+ coco_string_delete(name); name = coco_string_create(t->val);
+ } else {
+ Get();
+ wchar_t *subName = coco_string_create(t->val, 1, coco_string_length(t->val)-2);
+ coco_string_delete(name);
+ name = coco_string_create_append(L"\"", subName);
+ coco_string_delete(subName);
+ coco_string_merge(name, L"\"");
+
+ }
+ kind = str;
+ if (dfa->ignoreCase) {
+ wchar_t *oldName = name;
+ name = coco_string_create_lower(name);
+ coco_string_delete(oldName);
+ }
+ if (coco_string_indexof(name, ' ') >= 0)
+ SemErr(L"literal tokens must not contain blanks");
+ } else SynErr(47);
+}
+
+void Parser::Term(Graph* &g) {
+ Graph *g2; Node *rslv = NULL; g = NULL;
+ if (StartOf(17)) {
+ if (la->kind == 37 /* "IF" */) {
+ rslv = tab->NewNode(Node::rslv, (Symbol*)NULL, la->line);
+ Resolver(rslv->pos);
+ g = new Graph(rslv);
+ }
+ Factor(g2);
+ if (rslv != NULL) tab->MakeSequence(g, g2);
+ else g = g2;
+ while (StartOf(18)) {
+ Factor(g2);
+ tab->MakeSequence(g, g2);
+ }
+ } else if (StartOf(19)) {
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0));
+ } else SynErr(48);
+ if (g == NULL) // invalid start of Term
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0));
+}
+
+void Parser::Resolver(Position* &pos) {
+ Expect(37 /* "IF" */);
+ Expect(30 /* "(" */);
+ int beg = la->pos; int col = la->col; int line = la->line;
+ Condition();
+ pos = new Position(beg, t->pos, col, line);
+}
+
+void Parser::Factor(Graph* &g) {
+ wchar_t* name = NULL; int kind; Position *pos; bool weak = false;
+ g = NULL;
+
+ switch (la->kind) {
+ case _ident: case _string: case _char: case 29 /* "WEAK" */: {
+ if (la->kind == 29 /* "WEAK" */) {
+ Get();
+ weak = true;
+ }
+ Sym(name, kind);
+ Symbol *sym = tab->FindSym(name);
+ if (sym == NULL && kind == str)
+ sym = (Symbol*)((*(tab->literals))[name]);
+ bool undef = (sym == NULL);
+ if (undef) {
+ if (kind == id)
+ sym = tab->NewSym(Node::nt, name, 0); // forward nt
+ else if (genScanner) {
+ sym = tab->NewSym(Node::t, name, t->line);
+ dfa->MatchLiteral(sym->name, sym);
+ } else { // undefined string in production
+ SemErr(L"undefined string in production");
+ sym = tab->eofSy; // dummy
+ }
+ }
+ int typ = sym->typ;
+ if (typ != Node::t && typ != Node::nt)
+ SemErr(L"this symbol kind is not allowed in a production");
+ if (weak) {
+ if (typ == Node::t) typ = Node::wt;
+ else SemErr(L"only terminals may be weak");
+ }
+ Node *p = tab->NewNode(typ, sym, t->line);
+ g = new Graph(p);
+
+ if (la->kind == 24 /* "<" */ || la->kind == 26 /* "<." */) {
+ Attribs(p);
+ if (kind != id) SemErr(L"a literal must not have attributes");
+ }
+ if (undef)
+ sym->attrPos = p->pos; // dummy
+ else if ((p->pos == NULL) != (sym->attrPos == NULL))
+ SemErr(L"attribute mismatch between declaration and use of this symbol");
+
+ break;
+ }
+ case 30 /* "(" */: {
+ Get();
+ Expression(g);
+ Expect(31 /* ")" */);
+ break;
+ }
+ case 32 /* "[" */: {
+ Get();
+ Expression(g);
+ Expect(33 /* "]" */);
+ tab->MakeOption(g);
+ break;
+ }
+ case 34 /* "{" */: {
+ Get();
+ Expression(g);
+ Expect(35 /* "}" */);
+ tab->MakeIteration(g);
+ break;
+ }
+ case 39 /* "(." */: {
+ SemText(pos);
+ Node *p = tab->NewNode(Node::sem, (Symbol*)NULL, 0);
+ p->pos = pos;
+ g = new Graph(p);
+
+ break;
+ }
+ case 23 /* "ANY" */: {
+ Get();
+ Node *p = tab->NewNode(Node::any, (Symbol*)NULL, 0); // p.set is set in tab->SetupAnys
+ g = new Graph(p);
+
+ break;
+ }
+ case 36 /* "SYNC" */: {
+ Get();
+ Node *p = tab->NewNode(Node::sync, (Symbol*)NULL, 0);
+ g = new Graph(p);
+
+ break;
+ }
+ default: SynErr(49); break;
+ }
+ if (g == NULL) // invalid start of Factor
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0));
+
+}
+
+void Parser::Attribs(Node *p) {
+ if (la->kind == 24 /* "<" */) {
+ Get();
+ int beg = la->pos; int col = la->col; int line = la->line;
+ while (StartOf(9)) {
+ if (StartOf(10)) {
+ Get();
+ } else {
+ Get();
+ SemErr(L"bad string in attributes");
+ }
+ }
+ Expect(25 /* ">" */);
+ if (t->pos > beg) p->pos = new Position(beg, t->pos, col, line);
+ } else if (la->kind == 26 /* "<." */) {
+ Get();
+ int beg = la->pos; int col = la->col; int line = la->line;
+ while (StartOf(11)) {
+ if (StartOf(12)) {
+ Get();
+ } else {
+ Get();
+ SemErr(L"bad string in attributes");
+ }
+ }
+ Expect(27 /* ".>" */);
+ if (t->pos > beg) p->pos = new Position(beg, t->pos, col, line);
+ } else SynErr(50);
+}
+
+void Parser::Condition() {
+ while (StartOf(20)) {
+ if (la->kind == 30 /* "(" */) {
+ Get();
+ Condition();
+ } else {
+ Get();
+ }
+ }
+ Expect(31 /* ")" */);
+}
+
+void Parser::TokenTerm(Graph* &g) {
+ Graph *g2;
+ TokenFactor(g);
+ while (StartOf(8)) {
+ TokenFactor(g2);
+ tab->MakeSequence(g, g2);
+ }
+ if (la->kind == 38 /* "CONTEXT" */) {
+ Get();
+ Expect(30 /* "(" */);
+ TokenExpr(g2);
+ tab->SetContextTrans(g2->l); dfa->hasCtxMoves = true;
+ tab->MakeSequence(g, g2);
+ Expect(31 /* ")" */);
+ }
+}
+
+void Parser::TokenFactor(Graph* &g) {
+ wchar_t* name = NULL; int kind;
+ g = NULL;
+ if (la->kind == _ident || la->kind == _string || la->kind == _char) {
+ Sym(name, kind);
+ if (kind == id) {
+ CharClass *c = tab->FindCharClass(name);
+ if (c == NULL) {
+ SemErr(L"undefined name");
+ c = tab->NewCharClass(name, new CharSet());
+ }
+ Node *p = tab->NewNode(Node::clas, (Symbol*)NULL, 0); p->val = c->n;
+ g = new Graph(p);
+ tokenString = coco_string_create(noString);
+ } else { // str
+ g = tab->StrToGraph(name);
+ if (tokenString == NULL) tokenString = coco_string_create(name);
+ else tokenString = coco_string_create(noString);
+ }
+
+ } else if (la->kind == 30 /* "(" */) {
+ Get();
+ TokenExpr(g);
+ Expect(31 /* ")" */);
+ } else if (la->kind == 32 /* "[" */) {
+ Get();
+ TokenExpr(g);
+ Expect(33 /* "]" */);
+ tab->MakeOption(g); tokenString = coco_string_create(noString);
+ } else if (la->kind == 34 /* "{" */) {
+ Get();
+ TokenExpr(g);
+ Expect(35 /* "}" */);
+ tab->MakeIteration(g); tokenString = coco_string_create(noString);
+ } else SynErr(51);
+ if (g == NULL) // invalid start of TokenFactor
+ g = new Graph(tab->NewNode(Node::eps, (Symbol*)NULL, 0));
+}
+
+
+
+
+// If the user declared a method Init and a mehtod Destroy they should
+// be called in the contructur and the destructor respctively.
+//
+// The following templates are used to recognize if the user declared
+// the methods Init and Destroy.
+
+template<typename T>
+struct ParserInitExistsRecognizer {
+ template<typename U, void (U::*)() = &U::Init>
+ struct ExistsIfInitIsDefinedMarker{};
+
+ struct InitIsMissingType {
+ char dummy1;
+ };
+
+ struct InitExistsType {
+ char dummy1; char dummy2;
+ };
+
+ // exists always
+ template<typename U>
+ static InitIsMissingType is_here(...);
+
+ // exist only if ExistsIfInitIsDefinedMarker is defined
+ template<typename U>
+ static InitExistsType is_here(ExistsIfInitIsDefinedMarker<U>*);
+
+ enum { InitExists = (sizeof(is_here<T>(NULL)) == sizeof(InitExistsType)) };
+};
+
+template<typename T>
+struct ParserDestroyExistsRecognizer {
+ template<typename U, void (U::*)() = &U::Destroy>
+ struct ExistsIfDestroyIsDefinedMarker{};
+
+ struct DestroyIsMissingType {
+ char dummy1;
+ };
+
+ struct DestroyExistsType {
+ char dummy1; char dummy2;
+ };
+
+ // exists always
+ template<typename U>
+ static DestroyIsMissingType is_here(...);
+
+ // exist only if ExistsIfDestroyIsDefinedMarker is defined
+ template<typename U>
+ static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker<U>*);
+
+ enum { DestroyExists = (sizeof(is_here<T>(NULL)) == sizeof(DestroyExistsType)) };
+};
+
+// The folloing templates are used to call the Init and Destroy methods if they exist.
+
+// Generic case of the ParserInitCaller, gets used if the Init method is missing
+template<typename T, bool = ParserInitExistsRecognizer<T>::InitExists>
+struct ParserInitCaller {
+ static void CallInit(T *t) {
+ // nothing to do
+ }
+};
+
+// True case of the ParserInitCaller, gets used if the Init method exists
+template<typename T>
+struct ParserInitCaller<T, true> {
+ static void CallInit(T *t) {
+ t->Init();
+ }
+};
+
+// Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
+template<typename T, bool = ParserDestroyExistsRecognizer<T>::DestroyExists>
+struct ParserDestroyCaller {
+ static void CallDestroy(T *t) {
+ // nothing to do
+ }
+};
+
+// True case of the ParserDestroyCaller, gets used if the Destroy method exists
+template<typename T>
+struct ParserDestroyCaller<T, true> {
+ static void CallDestroy(T *t) {
+ t->Destroy();
+ }
+};
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+ Coco();
+ Expect(0);
+}
+
+Parser::Parser(Scanner *scanner) {
+ maxT = 41;
+
+ ParserInitCaller<Parser>::CallInit(this);
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+ static bool set[21][43] = {
+ {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x},
+ {x,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {x,T,T,T, T,T,T,x, x,x,x,x, T,T,T,x, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,T,x, x,x,x,T, x,x,x,x, T,T,T,x, T,x,T,x, T,T,x,T, x,x,x},
+ {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x},
+ {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x},
+ {x,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,T, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,x,T, x,x,x,x, x,x,x},
+ {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, T,x,T,x, x,x,x,x, x,x,x},
+ {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x},
+ {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,x},
+ {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, x,T,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,x,T, x,x,x,x, x,x,x},
+ {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,T, x,x,x,x, T,T,T,T, T,T,T,T, T,T,x,T, x,x,x},
+ {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,T,x, T,x,T,x, T,T,x,T, x,x,x},
+ {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,T,x, T,x,T,x, T,x,x,T, x,x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, T,x,x,T, x,T,x,T, x,x,x,x, x,x,x},
+ {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,x}
+ };
+
+
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ ParserDestroyCaller<Parser>::CallDestroy(this);
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+ case 0: s = coco_string_create(L"EOF expected"); break;
+ case 1: s = coco_string_create(L"ident expected"); break;
+ case 2: s = coco_string_create(L"number expected"); break;
+ case 3: s = coco_string_create(L"string expected"); break;
+ case 4: s = coco_string_create(L"badString expected"); break;
+ case 5: s = coco_string_create(L"char expected"); break;
+ case 6: s = coco_string_create(L"\"COMPILER\" expected"); break;
+ case 7: s = coco_string_create(L"\"IGNORECASE\" expected"); break;
+ case 8: s = coco_string_create(L"\"CHARACTERS\" expected"); break;
+ case 9: s = coco_string_create(L"\"TOKENS\" expected"); break;
+ case 10: s = coco_string_create(L"\"PRAGMAS\" expected"); break;
+ case 11: s = coco_string_create(L"\"COMMENTS\" expected"); break;
+ case 12: s = coco_string_create(L"\"FROM\" expected"); break;
+ case 13: s = coco_string_create(L"\"TO\" expected"); break;
+ case 14: s = coco_string_create(L"\"NESTED\" expected"); break;
+ case 15: s = coco_string_create(L"\"IGNORE\" expected"); break;
+ case 16: s = coco_string_create(L"\"PRODUCTIONS\" expected"); break;
+ case 17: s = coco_string_create(L"\"=\" expected"); break;
+ case 18: s = coco_string_create(L"\".\" expected"); break;
+ case 19: s = coco_string_create(L"\"END\" expected"); break;
+ case 20: s = coco_string_create(L"\"+\" expected"); break;
+ case 21: s = coco_string_create(L"\"-\" expected"); break;
+ case 22: s = coco_string_create(L"\"..\" expected"); break;
+ case 23: s = coco_string_create(L"\"ANY\" expected"); break;
+ case 24: s = coco_string_create(L"\"<\" expected"); break;
+ case 25: s = coco_string_create(L"\">\" expected"); break;
+ case 26: s = coco_string_create(L"\"<.\" expected"); break;
+ case 27: s = coco_string_create(L"\".>\" expected"); break;
+ case 28: s = coco_string_create(L"\"|\" expected"); break;
+ case 29: s = coco_string_create(L"\"WEAK\" expected"); break;
+ case 30: s = coco_string_create(L"\"(\" expected"); break;
+ case 31: s = coco_string_create(L"\")\" expected"); break;
+ case 32: s = coco_string_create(L"\"[\" expected"); break;
+ case 33: s = coco_string_create(L"\"]\" expected"); break;
+ case 34: s = coco_string_create(L"\"{\" expected"); break;
+ case 35: s = coco_string_create(L"\"}\" expected"); break;
+ case 36: s = coco_string_create(L"\"SYNC\" expected"); break;
+ case 37: s = coco_string_create(L"\"IF\" expected"); break;
+ case 38: s = coco_string_create(L"\"CONTEXT\" expected"); break;
+ case 39: s = coco_string_create(L"\"(.\" expected"); break;
+ case 40: s = coco_string_create(L"\".)\" expected"); break;
+ case 41: s = coco_string_create(L"??? expected"); break;
+ case 42: s = coco_string_create(L"this symbol not expected in Coco"); break;
+ case 43: s = coco_string_create(L"this symbol not expected in TokenDecl"); break;
+ case 44: s = coco_string_create(L"invalid TokenDecl"); break;
+ case 45: s = coco_string_create(L"invalid AttrDecl"); break;
+ case 46: s = coco_string_create(L"invalid SimSet"); break;
+ case 47: s = coco_string_create(L"invalid Sym"); break;
+ case 48: s = coco_string_create(L"invalid Term"); break;
+ case 49: s = coco_string_create(L"invalid Factor"); break;
+ case 50: s = coco_string_create(L"invalid Attribs"); break;
+ case 51: s = coco_string_create(L"invalid TokenFactor"); break;
+
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+} // namespace
+
diff --git a/old/cococpp/Parser.frame b/old/cococpp/Parser.frame
new file mode 100644
index 0000000..85bd8b5
--- /dev/null
+++ b/old/cococpp/Parser.frame
@@ -0,0 +1,326 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Parser.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(-->prefixCOCO_PARSER_H__)
+#define -->prefixCOCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+
+// If the user declared a method Init and a mehtod Destroy they should
+// be called in the contructur and the destructor respctively.
+//
+// The following templates are used to recognize if the user declared
+// the methods Init and Destroy.
+
+template<typename T>
+struct ParserInitExistsRecognizer {
+ template<typename U, void (U::*)() = &U::Init>
+ struct ExistsIfInitIsDefinedMarker{};
+
+ struct InitIsMissingType {
+ char dummy1;
+ };
+
+ struct InitExistsType {
+ char dummy1; char dummy2;
+ };
+
+ // exists always
+ template<typename U>
+ static InitIsMissingType is_here(...);
+
+ // exist only if ExistsIfInitIsDefinedMarker is defined
+ template<typename U>
+ static InitExistsType is_here(ExistsIfInitIsDefinedMarker<U>*);
+
+ enum { InitExists = (sizeof(is_here<T>(NULL)) == sizeof(InitExistsType)) };
+};
+
+template<typename T>
+struct ParserDestroyExistsRecognizer {
+ template<typename U, void (U::*)() = &U::Destroy>
+ struct ExistsIfDestroyIsDefinedMarker{};
+
+ struct DestroyIsMissingType {
+ char dummy1;
+ };
+
+ struct DestroyExistsType {
+ char dummy1; char dummy2;
+ };
+
+ // exists always
+ template<typename U>
+ static DestroyIsMissingType is_here(...);
+
+ // exist only if ExistsIfDestroyIsDefinedMarker is defined
+ template<typename U>
+ static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker<U>*);
+
+ enum { DestroyExists = (sizeof(is_here<T>(NULL)) == sizeof(DestroyExistsType)) };
+};
+
+// The folloing templates are used to call the Init and Destroy methods if they exist.
+
+// Generic case of the ParserInitCaller, gets used if the Init method is missing
+template<typename T, bool = ParserInitExistsRecognizer<T>::InitExists>
+struct ParserInitCaller {
+ static void CallInit(T *t) {
+ // nothing to do
+ }
+};
+
+// True case of the ParserInitCaller, gets used if the Init method exists
+template<typename T>
+struct ParserInitCaller<T, true> {
+ static void CallInit(T *t) {
+ t->Init();
+ }
+};
+
+// Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
+template<typename T, bool = ParserDestroyExistsRecognizer<T>::DestroyExists>
+struct ParserDestroyCaller {
+ static void CallDestroy(T *t) {
+ // nothing to do
+ }
+};
+
+// True case of the ParserDestroyCaller, gets used if the Destroy method exists
+template<typename T>
+struct ParserDestroyCaller<T, true> {
+ static void CallDestroy(T *t) {
+ t->Destroy();
+ }
+};
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ ParserInitCaller<Parser>::CallInit(this);
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ ParserDestroyCaller<Parser>::CallDestroy(this);
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cococpp/Parser.h b/old/cococpp/Parser.h
new file mode 100644
index 0000000..3a3460c
--- /dev/null
+++ b/old/cococpp/Parser.h
@@ -0,0 +1,153 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+
+#if !defined(Coco_COCO_PARSER_H__)
+#define Coco_COCO_PARSER_H__
+
+#include "Tab.h"
+#include "DFA.h"
+#include "ParserGen.h"
+
+
+#include "Scanner.h"
+
+namespace Coco {
+
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+ enum {
+ _EOF=0,
+ _ident=1,
+ _number=2,
+ _string=3,
+ _badString=4,
+ _char=5,
+ _ddtSym=42,
+ _optionSym=43
+ };
+ int maxT;
+
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+int id;
+ int str;
+
+ FILE* trace; // other Coco objects referenced in this ATG
+ Tab *tab;
+ DFA *dfa;
+ ParserGen *pgen;
+
+ bool genScanner;
+ wchar_t* tokenString; // used in declarations of literal tokens
+ wchar_t* noString; // used in declarations of literal tokens
+
+ // This method will be called by the contructor if it exits.
+ // This support is specific to the C++ version of Coco/R.
+ void Init() {
+ tab = NULL;
+ dfa = NULL;
+ pgen = NULL;
+ id = 0;
+ str = 1;
+ tokenString = NULL;
+ noString = coco_string_create(L"-none-");
+ }
+
+ // Uncomment this method if cleanup is necessary,
+ // this method will be called by the destructor if it exists.
+ // This support is specific to the C++ version of Coco/R.
+ // void Destroy() {
+ // nothing to do
+ // }
+/*-------------------------------------------------------------------------*/
+
+
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+ void Coco();
+ void SetDecl();
+ void TokenDecl(int typ);
+ void TokenExpr(Graph* &g);
+ void Set(CharSet* &s);
+ void AttrDecl(Symbol *sym);
+ void SemText(Position* &pos);
+ void Expression(Graph* &g);
+ void SimSet(CharSet* &s);
+ void Char(int &n);
+ void Sym(wchar_t* &name, int &kind);
+ void Term(Graph* &g);
+ void Resolver(Position* &pos);
+ void Factor(Graph* &g);
+ void Attribs(Node *p);
+ void Condition();
+ void TokenTerm(Graph* &g);
+ void TokenFactor(Graph* &g);
+
+ void Parse();
+
+}; // end Parser
+
+} // namespace
+
+
+#endif
+
diff --git a/old/cococpp/ParserGen.cpp b/old/cococpp/ParserGen.cpp
new file mode 100644
index 0000000..ee8e938
--- /dev/null
+++ b/old/cococpp/ParserGen.cpp
@@ -0,0 +1,486 @@
+/*-------------------------------------------------------------------------
+ParserGen -- Generation of the Recursive Descent Parser
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <ctype.h>
+#include "ArrayList.h"
+#include "ParserGen.h"
+#include "Parser.h"
+#include "BitArray.h"
+#include "Scanner.h"
+#include "Generator.h"
+
+namespace Coco {
+
+void ParserGen::Indent (int n) {
+ for (int i = 1; i <= n; i++) fwprintf(gen, L"\t");
+}
+
+// use a switch if more than 5 alternatives and none starts with a resolver, and no LL1 warning
+bool ParserGen::UseSwitch (Node *p) {
+ BitArray *s1, *s2;
+ if (p->typ != Node::alt) return false;
+ int nAlts = 0;
+ s1 = new BitArray(tab->terminals->Count);
+ while (p != NULL) {
+ s2 = tab->Expected0(p->sub, curSy);
+ // must not optimize with switch statement, if there are ll1 warnings
+ if (s1->Overlaps(s2)) { return false; }
+ s1->Or(s2);
+ ++nAlts;
+ // must not optimize with switch-statement, if alt uses a resolver expression
+ if (p->sub->typ == Node::rslv) return false;
+ p = p->down;
+ }
+ return nAlts > 5;
+}
+
+int ParserGen::GenNamespaceOpen(const wchar_t *nsName) {
+ if (nsName == NULL || coco_string_length(nsName) == 0) {
+ return 0;
+ }
+ const int len = coco_string_length(nsName);
+ int startPos = 0;
+ int nrOfNs = 0;
+ do {
+ int curLen = coco_string_indexof(nsName + startPos, COCO_CPP_NAMESPACE_SEPARATOR);
+ if (curLen == -1) { curLen = len - startPos; }
+ wchar_t *curNs = coco_string_create(nsName, startPos, curLen);
+ fwprintf(gen, L"namespace %ls {\n", curNs);
+ coco_string_delete(curNs);
+ startPos = startPos + curLen + 1;
+ if (startPos < len && nsName[startPos] == COCO_CPP_NAMESPACE_SEPARATOR) {
+ ++startPos;
+ }
+ ++nrOfNs;
+ } while (startPos < len);
+ return nrOfNs;
+}
+
+void ParserGen::GenNamespaceClose(int nrOfNs) {
+ for (int i = 0; i < nrOfNs; ++i) {
+ fwprintf(gen, L"} // namespace\n");
+ }
+}
+
+void ParserGen::CopySourcePart (Position *pos, int indent) {
+ // Copy text described by pos from atg to gen
+ int ch, i;
+ if (pos != NULL) {
+ buffer->SetPos(pos->beg); ch = buffer->Read();
+ if (tab->emitLines && pos->line) {
+ fwprintf(gen, L"\n#line %d \"%ls\"\n", pos->line, tab->srcName);
+ }
+ Indent(indent);
+ while (buffer->GetPos() <= pos->end) {
+ while (ch == CR || ch == LF) { // eol is either CR or CRLF or LF
+ fwprintf(gen, L"\n"); Indent(indent);
+ if (ch == CR) { ch = buffer->Read(); } // skip CR
+ if (ch == LF) { ch = buffer->Read(); } // skip LF
+ for (i = 1; i <= pos->col && (ch == ' ' || ch == '\t'); i++) {
+ // skip blanks at beginning of line
+ ch = buffer->Read();
+ }
+ if (buffer->GetPos() > pos->end) goto done;
+ }
+ fwprintf(gen, L"%lc", ch);
+ ch = buffer->Read();
+ }
+ done:
+ if (indent > 0) fwprintf(gen, L"\n");
+ }
+}
+
+void ParserGen::GenErrorMsg (int errTyp, Symbol *sym) {
+ errorNr++;
+ const int formatLen = 1000;
+ wchar_t format[formatLen];
+ coco_swprintf(format, formatLen, L"\t\t\tcase %d: s = coco_string_create(L\"", errorNr);
+ coco_string_merge(err, format);
+ if (errTyp == tErr) {
+ if (sym->name[0] == L'"') {
+ coco_swprintf(format, formatLen, L"%ls expected", tab->Escape(sym->name));
+ coco_string_merge(err, format);
+ } else {
+ coco_swprintf(format, formatLen, L"%ls expected", sym->name);
+ coco_string_merge(err, format);
+ }
+ } else if (errTyp == altErr) {
+ coco_swprintf(format, formatLen, L"invalid %ls", sym->name);
+ coco_string_merge(err, format);
+ } else if (errTyp == syncErr) {
+ coco_swprintf(format, formatLen, L"this symbol not expected in %ls", sym->name);
+ coco_string_merge(err, format);
+ }
+ coco_swprintf(format, formatLen, L"\"); break;\n");
+ coco_string_merge(err, format);
+}
+
+int ParserGen::NewCondSet (BitArray *s) {
+ for (int i = 1; i < symSet->Count; i++) // skip symSet[0] (reserved for union of SYNC sets)
+ if (Sets::Equals(s, (BitArray*)(*symSet)[i])) return i;
+ symSet->Add(s->Clone());
+ return symSet->Count - 1;
+}
+
+void ParserGen::GenCond (BitArray *s, Node *p) {
+ if (p->typ == Node::rslv) CopySourcePart(p->pos, 0);
+ else {
+ int n = Sets::Elements(s);
+ if (n == 0) fwprintf(gen, L"false"); // happens if an ANY set matches no symbol
+ else if (n <= maxTerm) {
+ Symbol *sym;
+ for (int i=0; i<tab->terminals->Count; i++) {
+ sym = (Symbol*)((*(tab->terminals))[i]);
+ if ((*s)[sym->n]) {
+ fwprintf(gen, L"la->kind == ");
+ WriteSymbolOrCode(gen, sym);
+ --n;
+ if (n > 0) fwprintf(gen, L" || ");
+ }
+ }
+ } else
+ fwprintf(gen, L"StartOf(%d)", NewCondSet(s));
+ }
+}
+
+void ParserGen::PutCaseLabels (BitArray *s) {
+ Symbol *sym;
+ for (int i=0; i<tab->terminals->Count; i++) {
+ sym = (Symbol*)((*(tab->terminals))[i]);
+ if ((*s)[sym->n]) {
+ fwprintf(gen, L"case ");
+ WriteSymbolOrCode(gen, sym);
+ fwprintf(gen, L": ");
+ }
+ }
+}
+
+void ParserGen::GenCode (Node *p, int indent, BitArray *isChecked) {
+ Node *p2;
+ BitArray *s1, *s2;
+ while (p != NULL) {
+ if (p->typ == Node::nt) {
+ Indent(indent);
+ fwprintf(gen, L"%ls(", p->sym->name);
+ CopySourcePart(p->pos, 0);
+ fwprintf(gen, L");\n");
+ } else if (p->typ == Node::t) {
+ Indent(indent);
+ // assert: if isChecked[p->sym->n] is true, then isChecked contains only p->sym->n
+ if ((*isChecked)[p->sym->n]) fwprintf(gen, L"Get();\n");
+ else {
+ fwprintf(gen, L"Expect(");
+ WriteSymbolOrCode(gen, p->sym);
+ fwprintf(gen, L");\n");
+ }
+ } if (p->typ == Node::wt) {
+ Indent(indent);
+ s1 = tab->Expected(p->next, curSy);
+ s1->Or(tab->allSyncSets);
+ fwprintf(gen, L"ExpectWeak(");
+ WriteSymbolOrCode(gen, p->sym);
+ fwprintf(gen, L", %d);\n", NewCondSet(s1));
+ } if (p->typ == Node::any) {
+ Indent(indent);
+ int acc = Sets::Elements(p->set);
+ if (tab->terminals->Count == (acc + 1) || (acc > 0 && Sets::Equals(p->set, isChecked))) {
+ // either this ANY accepts any terminal (the + 1 = end of file), or exactly what's allowed here
+ fwprintf(gen, L"Get();\n");
+ } else {
+ GenErrorMsg(altErr, curSy);
+ if (acc > 0) {
+ fwprintf(gen, L"if ("); GenCond(p->set, p); fwprintf(gen, L") Get(); else SynErr(%d);\n", errorNr);
+ } else fwprintf(gen, L"SynErr(%d); // ANY node that matches no symbol\n", errorNr);
+ }
+ } if (p->typ == Node::eps) { // nothing
+ } if (p->typ == Node::rslv) { // nothing
+ } if (p->typ == Node::sem) {
+ CopySourcePart(p->pos, indent);
+ } if (p->typ == Node::sync) {
+ Indent(indent);
+ GenErrorMsg(syncErr, curSy);
+ s1 = p->set->Clone();
+ fwprintf(gen, L"while (!("); GenCond(s1, p); fwprintf(gen, L")) {");
+ fwprintf(gen, L"SynErr(%d); Get();", errorNr); fwprintf(gen, L"}\n");
+ } if (p->typ == Node::alt) {
+ s1 = tab->First(p);
+ bool equal = Sets::Equals(s1, isChecked);
+ bool useSwitch = UseSwitch(p);
+ if (useSwitch) { Indent(indent); fwprintf(gen, L"switch (la->kind) {\n"); }
+ p2 = p;
+ while (p2 != NULL) {
+ s1 = tab->Expected(p2->sub, curSy);
+ Indent(indent);
+ if (useSwitch) {
+ PutCaseLabels(s1); fwprintf(gen, L"{\n");
+ } else if (p2 == p) {
+ fwprintf(gen, L"if ("); GenCond(s1, p2->sub); fwprintf(gen, L") {\n");
+ } else if (p2->down == NULL && equal) { fwprintf(gen, L"} else {\n");
+ } else {
+ fwprintf(gen, L"} else if ("); GenCond(s1, p2->sub); fwprintf(gen, L") {\n");
+ }
+ GenCode(p2->sub, indent + 1, s1);
+ if (useSwitch) {
+ Indent(indent); fwprintf(gen, L"\tbreak;\n");
+ Indent(indent); fwprintf(gen, L"}\n");
+ }
+ p2 = p2->down;
+ }
+ Indent(indent);
+ if (equal) {
+ fwprintf(gen, L"}\n");
+ } else {
+ GenErrorMsg(altErr, curSy);
+ if (useSwitch) {
+ fwprintf(gen, L"default: SynErr(%d); break;\n", errorNr);
+ Indent(indent); fwprintf(gen, L"}\n");
+ } else {
+ fwprintf(gen, L"} "); fwprintf(gen, L"else SynErr(%d);\n", errorNr);
+ }
+ }
+ } if (p->typ == Node::iter) {
+ Indent(indent);
+ p2 = p->sub;
+ fwprintf(gen, L"while (");
+ if (p2->typ == Node::wt) {
+ s1 = tab->Expected(p2->next, curSy);
+ s2 = tab->Expected(p->next, curSy);
+ fwprintf(gen, L"WeakSeparator(");
+ WriteSymbolOrCode(gen, p2->sym);
+ fwprintf(gen, L",%d,%d) ", NewCondSet(s1), NewCondSet(s2));
+ s1 = new BitArray(tab->terminals->Count); // for inner structure
+ if (p2->up || p2->next == NULL) p2 = NULL; else p2 = p2->next;
+ } else {
+ s1 = tab->First(p2);
+ GenCond(s1, p2);
+ }
+ fwprintf(gen, L") {\n");
+ GenCode(p2, indent + 1, s1);
+ Indent(indent); fwprintf(gen, L"}\n");
+ } if (p->typ == Node::opt) {
+ s1 = tab->First(p->sub);
+ Indent(indent);
+ fwprintf(gen, L"if ("); GenCond(s1, p->sub); fwprintf(gen, L") {\n");
+ GenCode(p->sub, indent + 1, s1);
+ Indent(indent); fwprintf(gen, L"}\n");
+ }
+ if (p->typ != Node::eps && p->typ != Node::sem && p->typ != Node::sync)
+ isChecked->SetAll(false); // = new BitArray(Symbol.terminals.Count);
+ if (p->up) break;
+ p = p->next;
+ }
+}
+
+
+void ParserGen::GenTokensHeader() {
+ Symbol *sym;
+ int i;
+ bool isFirst = true;
+
+ fwprintf(gen, L"\tenum {\n");
+
+ // tokens
+ for (i=0; i<tab->terminals->Count; i++) {
+ sym = (Symbol*)((*(tab->terminals))[i]);
+ if (!isalpha(sym->name[0])) { continue; }
+
+ if (isFirst) { isFirst = false; }
+ else { fwprintf(gen , L",\n"); }
+
+ fwprintf(gen , L"\t\t_%ls=%d", sym->name, sym->n);
+ }
+
+ // pragmas
+ for (i=0; i<tab->pragmas->Count; i++) {
+ if (isFirst) { isFirst = false; }
+ else { fwprintf(gen , L",\n"); }
+
+ sym = (Symbol*)((*(tab->pragmas))[i]);
+ fwprintf(gen , L"\t\t_%ls=%d", sym->name, sym->n);
+ }
+
+ fwprintf(gen, L"\n\t};\n");
+}
+
+void ParserGen::GenCodePragmas() {
+ Symbol *sym;
+ for (int i=0; i<tab->pragmas->Count; i++) {
+ sym = (Symbol*)((*(tab->pragmas))[i]);
+ fwprintf(gen, L"\t\tif (la->kind == ");
+ WriteSymbolOrCode(gen, sym);
+ fwprintf(gen, L") {\n");
+ CopySourcePart(sym->semPos, 4);
+ fwprintf(gen, L"\t\t}\n");
+ }
+}
+
+void ParserGen::WriteSymbolOrCode(FILE *gen, const Symbol *sym) {
+ if (!isalpha(sym->name[0])) {
+ fwprintf(gen, L"%d /* %ls */", sym->n, sym->name);
+ } else {
+ fwprintf(gen, L"_%ls", sym->name);
+ }
+}
+
+void ParserGen::GenProductionsHeader() {
+ Symbol *sym;
+ for (int i=0; i<tab->nonterminals->Count; i++) {
+ sym = (Symbol*)((*(tab->nonterminals))[i]);
+ curSy = sym;
+ fwprintf(gen, L"\tvoid %ls(", sym->name);
+ CopySourcePart(sym->attrPos, 0);
+ fwprintf(gen, L");\n");
+ }
+}
+
+void ParserGen::GenProductions() {
+ Symbol *sym;
+ for (int i=0; i<tab->nonterminals->Count; i++) {
+ sym = (Symbol*)((*(tab->nonterminals))[i]);
+ curSy = sym;
+ fwprintf(gen, L"void Parser::%ls(", sym->name);
+ CopySourcePart(sym->attrPos, 0);
+ fwprintf(gen, L") {\n");
+ CopySourcePart(sym->semPos, 2);
+ GenCode(sym->graph, 2, new BitArray(tab->terminals->Count));
+ fwprintf(gen, L"}\n"); fwprintf(gen, L"\n");
+ }
+}
+
+void ParserGen::InitSets() {
+ fwprintf(gen, L"\tstatic bool set[%d][%d] = {\n", symSet->Count, tab->terminals->Count+1);
+
+ for (int i = 0; i < symSet->Count; i++) {
+ BitArray *s = (BitArray*)(*symSet)[i];
+ fwprintf(gen, L"\t\t{");
+ int j = 0;
+ Symbol *sym;
+ for (int k=0; k<tab->terminals->Count; k++) {
+ sym = (Symbol*)((*(tab->terminals))[k]);
+ if ((*s)[sym->n]) fwprintf(gen, L"T,"); else fwprintf(gen, L"x,");
+ ++j;
+ if (j%4 == 0) fwprintf(gen, L" ");
+ }
+ if (i == symSet->Count-1) fwprintf(gen, L"x}\n"); else fwprintf(gen, L"x},\n");
+ }
+ fwprintf(gen, L"\t};\n\n");
+}
+
+void ParserGen::WriteParser () {
+ Generator g = Generator(tab, errors);
+ int oldPos = buffer->GetPos(); // Pos is modified by CopySourcePart
+ symSet->Add(tab->allSyncSets);
+
+ fram = g.OpenFrame(L"Parser.frame");
+ gen = g.OpenGen(L"Parser.h");
+
+ Symbol *sym;
+ for (int i=0; i<tab->terminals->Count; i++) {
+ sym = (Symbol*)((*(tab->terminals))[i]);
+ GenErrorMsg(tErr, sym);
+ }
+
+ g.GenCopyright();
+ g.SkipFramePart(L"-->begin");
+
+ g.CopyFramePart(L"-->prefix");
+ g.GenPrefixFromNamespace();
+
+ g.CopyFramePart(L"-->prefix");
+ g.GenPrefixFromNamespace();
+
+ g.CopyFramePart(L"-->headerdef");
+
+ if (usingPos != NULL) {CopySourcePart(usingPos, 0); fwprintf(gen, L"\n");}
+ g.CopyFramePart(L"-->namespace_open");
+ int nrOfNs = GenNamespaceOpen(tab->nsName);
+
+ g.CopyFramePart(L"-->constantsheader");
+ GenTokensHeader(); /* ML 2002/09/07 write the token kinds */
+ fwprintf(gen, L"\tint maxT;\n");
+ g.CopyFramePart(L"-->declarations"); CopySourcePart(tab->semDeclPos, 0);
+ g.CopyFramePart(L"-->productionsheader"); GenProductionsHeader();
+ g.CopyFramePart(L"-->namespace_close");
+ GenNamespaceClose(nrOfNs);
+
+ g.CopyFramePart(L"-->implementation");
+ fclose(gen);
+
+ // Source
+ gen = g.OpenGen(L"Parser.cpp");
+
+ g.GenCopyright();
+ g.SkipFramePart(L"-->begin");
+ g.CopyFramePart(L"-->namespace_open");
+ nrOfNs = GenNamespaceOpen(tab->nsName);
+
+ g.CopyFramePart(L"-->pragmas"); GenCodePragmas();
+ g.CopyFramePart(L"-->productions"); GenProductions();
+ g.CopyFramePart(L"-->parseRoot"); fwprintf(gen, L"\t%ls();\n", tab->gramSy->name); if (tab->checkEOF) fwprintf(gen, L"\tExpect(0);");
+ g.CopyFramePart(L"-->constants");
+ fwprintf(gen, L"\tmaxT = %d;\n", tab->terminals->Count-1);
+ g.CopyFramePart(L"-->initialization"); InitSets();
+ g.CopyFramePart(L"-->errors"); fwprintf(gen, L"%ls", err);
+ g.CopyFramePart(L"-->namespace_close");
+ GenNamespaceClose(nrOfNs);
+ g.CopyFramePart(NULL);
+ fclose(gen);
+ buffer->SetPos(oldPos);
+}
+
+
+void ParserGen::WriteStatistics () {
+ fwprintf(trace, L"\n");
+ fwprintf(trace, L"%d terminals\n", tab->terminals->Count);
+ fwprintf(trace, L"%d symbols\n", tab->terminals->Count + tab->pragmas->Count +
+ tab->nonterminals->Count);
+ fwprintf(trace, L"%d nodes\n", tab->nodes->Count);
+ fwprintf(trace, L"%d sets\n", symSet->Count);
+}
+
+
+ParserGen::ParserGen (Parser *parser) {
+ maxTerm = 3;
+ CR = '\r';
+ LF = '\n';
+ tErr = 0;
+ altErr = 1;
+ syncErr = 2;
+ tab = parser->tab;
+ errors = parser->errors;
+ trace = parser->trace;
+ buffer = parser->scanner->buffer;
+ errorNr = -1;
+ usingPos = NULL;
+
+ symSet = new ArrayList();
+ err = NULL;
+}
+
+}; // namespace
diff --git a/old/cococpp/ParserGen.h b/old/cococpp/ParserGen.h
new file mode 100644
index 0000000..ac6dd05
--- /dev/null
+++ b/old/cococpp/ParserGen.h
@@ -0,0 +1,99 @@
+/*-------------------------------------------------------------------------
+ParserGen -- Generation of the Recursive Descent Parser
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_PARSERGEN_H__)
+#define COCO_PARSERGEN_H__
+
+#include "Position.h"
+#include "Tab.h"
+#include "Symbol.h"
+#include "Scanner.h"
+#include "DFA.h"
+
+namespace Coco {
+
+class Errors;
+class Parser;
+class BitArray;
+
+class ParserGen
+{
+public:
+ int maxTerm; // sets of size < maxTerm are enumerated
+ char CR;
+ char LF;
+
+ int tErr; // error codes
+ int altErr;
+ int syncErr;
+
+ Position *usingPos; // "using" definitions from the attributed grammar
+
+ int errorNr; // highest parser error number
+ Symbol *curSy; // symbol whose production is currently generated
+ FILE* fram; // parser frame file
+ FILE* gen; // generated parser source file
+ wchar_t* err; // generated parser error messages
+ ArrayList *symSet;
+
+ Tab *tab; // other Coco objects
+ FILE* trace;
+ Errors *errors;
+ Buffer *buffer;
+
+ void Indent(int n);
+ bool UseSwitch(Node *p);
+ void CopyFramePart(const wchar_t* stop);
+ void CopySourcePart(Position *pos, int indent);
+ int GenNamespaceOpen(const wchar_t* nsName);
+ void GenNamespaceClose(int nrOfNs);
+ void GenErrorMsg(int errTyp, Symbol *sym);
+ int NewCondSet(BitArray *s);
+ void GenCond(BitArray *s, Node *p);
+ void PutCaseLabels(BitArray *s);
+ void GenCode(Node *p, int indent, BitArray *isChecked);
+ void GenTokens();
+ void GenTokensHeader();
+ void GenPragmas();
+ void GenPragmasHeader();
+ void GenCodePragmas();
+ void GenProductions();
+ void GenProductionsHeader();
+ void InitSets();
+ void OpenGen(const wchar_t* genName, bool backUp);
+ void WriteParser();
+ void WriteStatistics();
+ void WriteSymbolOrCode(FILE *gen, const Symbol *sym);
+ ParserGen (Parser *parser);
+
+};
+
+}; // namespace
+
+#endif // !defined(COCO_PARSERGEN_H__)
diff --git a/old/cococpp/Position.cpp b/old/cococpp/Position.cpp
new file mode 100644
index 0000000..1a75bac
--- /dev/null
+++ b/old/cococpp/Position.cpp
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Position.h"
+
+namespace Coco {
+
+Position::Position(int beg, int end, int col, int line) {
+ this->beg = beg; this->end = end; this->col = col; this->line = line;
+}
+
+}; // namespace
diff --git a/old/cococpp/Position.h b/old/cococpp/Position.h
new file mode 100644
index 0000000..052713b
--- /dev/null
+++ b/old/cococpp/Position.h
@@ -0,0 +1,46 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_POSITION_H__)
+#define COCO_POSITION_H__
+
+namespace Coco {
+
+class Position { // position of source code stretch (e.g. semantic action, resolver expressions)
+public:
+ int beg; // start relative to the beginning of the file
+ int end; // end of stretch
+ int col; // column number of start position
+ int line; // line number of beginnnig of source code stretch
+
+ Position(int beg, int end, int col, int line);
+};
+
+}; // namespace
+
+#endif // !defined(COCO_POSITION_H__)
diff --git a/old/cococpp/Scanner.cpp b/old/cococpp/Scanner.cpp
new file mode 100644
index 0000000..b3f4dd0
--- /dev/null
+++ b/old/cococpp/Scanner.cpp
@@ -0,0 +1,833 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+
+#include <memory.h>
+#include <string.h>
+#include "Scanner.h"
+
+namespace Coco {
+
+
+
+// string handling, wide character
+
+
+wchar_t* coco_string_create(const wchar_t* value) {
+ return coco_string_create(value, 0);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex) {
+ int valueLen = 0;
+ int len = 0;
+
+ if (value) {
+ valueLen = wcslen(value);
+ len = valueLen - startIndex;
+ }
+
+ return coco_string_create(value, startIndex, len);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) {
+ int len = 0;
+ wchar_t* data;
+
+ if (value) { len = length; }
+ data = new wchar_t[len + 1];
+ wcsncpy(data, &(value[startIndex]), len);
+ data[len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_upper(const wchar_t* data) {
+ if (!data) { return NULL; }
+
+ int dataLen = 0;
+ if (data) { dataLen = wcslen(data); }
+
+ wchar_t *newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ if ((L'a' <= data[i]) && (data[i] <= L'z')) {
+ newData[i] = data[i] + (L'A' - L'a');
+ }
+ else { newData[i] = data[i]; }
+ }
+
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data) {
+ if (!data) { return NULL; }
+ int dataLen = wcslen(data);
+ return coco_string_create_lower(data, 0, dataLen);
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) {
+ if (!data) { return NULL; }
+
+ wchar_t* newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ wchar_t ch = data[startIndex + i];
+ if ((L'A' <= ch) && (ch <= L'Z')) {
+ newData[i] = ch - (L'A' - L'a');
+ }
+ else { newData[i] = ch; }
+ }
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) {
+ wchar_t* data;
+ int data1Len = 0;
+ int data2Len = 0;
+
+ if (data1) { data1Len = wcslen(data1); }
+ if (data2) {data2Len = wcslen(data2); }
+
+ data = new wchar_t[data1Len + data2Len + 1];
+
+ if (data1) { wcscpy(data, data1); }
+ if (data2) { wcscpy(data + data1Len, data2); }
+
+ data[data1Len + data2Len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) {
+ int targetLen = coco_string_length(target);
+ wchar_t* data = new wchar_t[targetLen + 2];
+ wcsncpy(data, target, targetLen);
+ data[targetLen] = appendix;
+ data[targetLen + 1] = 0;
+ return data;
+}
+
+void coco_string_delete(wchar_t* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+int coco_string_length(const wchar_t* data) {
+ if (data) { return wcslen(data); }
+ return 0;
+}
+
+bool coco_string_endswith(const wchar_t* data, const wchar_t *end) {
+ int dataLen = wcslen(data);
+ int endLen = wcslen(end);
+ return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0);
+}
+
+int coco_string_indexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcschr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcsrchr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+void coco_string_merge(wchar_t* &target, const wchar_t* appendix) {
+ if (!appendix) { return; }
+ wchar_t* data = coco_string_create_append(target, appendix);
+ delete [] target;
+ target = data;
+}
+
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp( data1, data2 ) == 0;
+}
+
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp(data1, data2);
+}
+
+int coco_string_hash(const wchar_t *data) {
+ int h = 0;
+ if (!data) { return 0; }
+ while (*data != 0) {
+ h = (h * 7) ^ *data;
+ ++data;
+ }
+ if (h < 0) { h = -h; }
+ return h;
+}
+
+// string handling, ascii character
+
+wchar_t* coco_string_create(const char* value) {
+ int len = 0;
+ if (value) { len = strlen(value); }
+ wchar_t* data = new wchar_t[len + 1];
+ for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; }
+ data[len] = 0;
+ return data;
+}
+
+char* coco_string_create_char(const wchar_t *value) {
+ int len = coco_string_length(value);
+ char *res = new char[len + 1];
+ for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; }
+ res[len] = 0;
+ return res;
+}
+
+void coco_string_delete(char* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+
+Token::Token() {
+ kind = 0;
+ pos = 0;
+ col = 0;
+ line = 0;
+ val = NULL;
+ next = NULL;
+}
+
+Token::~Token() {
+ coco_string_delete(val);
+}
+
+Buffer::Buffer(FILE* s, bool isUserStream) {
+// ensure binary read on windows
+#if _MSC_VER >= 1300
+ _setmode(_fileno(s), _O_BINARY);
+#endif
+ stream = s; this->isUserStream = isUserStream;
+ if (CanSeek()) {
+ fseek(s, 0, SEEK_END);
+ fileLen = ftell(s);
+ fseek(s, 0, SEEK_SET);
+ bufLen = (fileLen < COCO_MAX_BUFFER_LENGTH) ? fileLen : COCO_MAX_BUFFER_LENGTH;
+ bufStart = INT_MAX; // nothing in the buffer so far
+ } else {
+ fileLen = bufLen = bufStart = 0;
+ }
+ bufCapacity = (bufLen>0) ? bufLen : COCO_MIN_BUFFER_LENGTH;
+ buf = new unsigned char[bufCapacity];
+ if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && CanSeek()) Close();
+}
+
+Buffer::Buffer(Buffer *b) {
+ buf = b->buf;
+ bufCapacity = b->bufCapacity;
+ b->buf = NULL;
+ bufStart = b->bufStart;
+ bufLen = b->bufLen;
+ fileLen = b->fileLen;
+ bufPos = b->bufPos;
+ stream = b->stream;
+ b->stream = NULL;
+ isUserStream = b->isUserStream;
+}
+
+Buffer::Buffer(const unsigned char* buf, int len) {
+ this->buf = new unsigned char[len];
+ memcpy(this->buf, buf, len*sizeof(unsigned char));
+ bufStart = 0;
+ bufCapacity = bufLen = len;
+ fileLen = len;
+ bufPos = 0;
+ stream = NULL;
+}
+
+Buffer::~Buffer() {
+ Close();
+ if (buf != NULL) {
+ delete [] buf;
+ buf = NULL;
+ }
+}
+
+void Buffer::Close() {
+ if (!isUserStream && stream != NULL) {
+ fclose(stream);
+ stream = NULL;
+ }
+}
+
+int Buffer::Read() {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (GetPos() < fileLen) {
+ SetPos(GetPos()); // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
+ return buf[bufPos++];
+ } else {
+ return EoF;
+ }
+}
+
+int Buffer::Peek() {
+ int curPos = GetPos();
+ int ch = Read();
+ SetPos(curPos);
+ return ch;
+}
+
+// beg .. begin, zero-based, inclusive, in byte
+// end .. end, zero-based, exclusive, in byte
+wchar_t* Buffer::GetString(int beg, int end) {
+ int len = 0;
+ wchar_t *buf = new wchar_t[end - beg];
+ int oldPos = GetPos();
+ SetPos(beg);
+ while (GetPos() < end) buf[len++] = (wchar_t) Read();
+ SetPos(oldPos);
+ wchar_t *res = coco_string_create(buf, 0, len);
+ coco_string_delete(buf);
+ return res;
+}
+
+int Buffer::GetPos() {
+ return bufPos + bufStart;
+}
+
+void Buffer::SetPos(int value) {
+ if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while ((value >= fileLen) && (ReadNextStreamChunk() > 0));
+ }
+
+ if ((value < 0) || (value > fileLen)) {
+ wprintf(L"--- buffer out of bounds access, position: %d\n", value);
+ exit(1);
+ }
+
+ if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != NULL) { // must be swapped in
+ fseek(stream, value, SEEK_SET);
+ bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
+ bufStart = value; bufPos = 0;
+ } else {
+ bufPos = fileLen - bufStart; // make Pos return fileLen
+ }
+}
+
+// Read the next chunk of bytes from the stream, increases the buffer
+// if needed and updates the fields fileLen and bufLen.
+// Returns the number of bytes read.
+int Buffer::ReadNextStreamChunk() {
+ int free = bufCapacity - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ bufCapacity = bufLen * 2;
+ unsigned char *newBuf = new unsigned char[bufCapacity];
+ memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
+ delete [] buf;
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = fread(buf + bufLen, sizeof(unsigned char), free, stream);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+}
+
+bool Buffer::CanSeek() {
+ return (stream != NULL) && (ftell(stream) != -1);
+}
+
+int UTF8Buffer::Read() {
+ int ch;
+ do {
+ ch = Buffer::Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
+ if (ch < 128 || ch == EoF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F; ch = Buffer::Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = Buffer::Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+}
+
+Scanner::Scanner(const unsigned char* buf, int len) {
+ buffer = new Buffer(buf, len);
+ Init();
+}
+
+Scanner::Scanner(const wchar_t* fileName) {
+ FILE* stream;
+ char *chFileName = coco_string_create_char(fileName);
+ if ((stream = fopen(chFileName, "rb")) == NULL) {
+ wprintf(L"--- Cannot open file %ls\n", fileName);
+ exit(1);
+ }
+ coco_string_delete(chFileName);
+ buffer = new Buffer(stream, false);
+ Init();
+}
+
+Scanner::Scanner(FILE* s) {
+ buffer = new Buffer(s, true);
+ Init();
+}
+
+Scanner::~Scanner() {
+ char* cur = (char*) firstHeap;
+
+ while(cur != NULL) {
+ cur = *(char**) (cur + COCO_HEAP_BLOCK_SIZE);
+ free(firstHeap);
+ firstHeap = cur;
+ }
+ delete [] tval;
+ delete buffer;
+}
+
+void Scanner::Init() {
+ EOL = '\n';
+ eofSym = 0;
+ maxT = 41;
+ noSym = 41;
+ int i;
+ for (i = 65; i <= 90; ++i) start.set(i, 1);
+ for (i = 95; i <= 95; ++i) start.set(i, 1);
+ for (i = 97; i <= 122; ++i) start.set(i, 1);
+ for (i = 48; i <= 57; ++i) start.set(i, 2);
+ start.set(34, 12);
+ start.set(39, 5);
+ start.set(36, 13);
+ start.set(61, 16);
+ start.set(46, 31);
+ start.set(43, 17);
+ start.set(45, 18);
+ start.set(60, 32);
+ start.set(62, 20);
+ start.set(124, 23);
+ start.set(40, 33);
+ start.set(41, 24);
+ start.set(91, 25);
+ start.set(93, 26);
+ start.set(123, 27);
+ start.set(125, 28);
+ start.set(Buffer::EoF, -1);
+ keywords.set(L"COMPILER", 6);
+ keywords.set(L"IGNORECASE", 7);
+ keywords.set(L"CHARACTERS", 8);
+ keywords.set(L"TOKENS", 9);
+ keywords.set(L"PRAGMAS", 10);
+ keywords.set(L"COMMENTS", 11);
+ keywords.set(L"FROM", 12);
+ keywords.set(L"TO", 13);
+ keywords.set(L"NESTED", 14);
+ keywords.set(L"IGNORE", 15);
+ keywords.set(L"PRODUCTIONS", 16);
+ keywords.set(L"END", 19);
+ keywords.set(L"ANY", 23);
+ keywords.set(L"WEAK", 29);
+ keywords.set(L"SYNC", 36);
+ keywords.set(L"IF", 37);
+ keywords.set(L"CONTEXT", 38);
+
+
+ tvalLength = 128;
+ tval = new wchar_t[tvalLength]; // text of current token
+
+ // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ heap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*));
+ firstHeap = heap;
+ heapEnd = (void**) (((char*) heap) + COCO_HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heapTop = heap;
+ if (sizeof(Token) > COCO_HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too small COCO_HEAP_BLOCK_SIZE\n");
+ exit(1);
+ }
+
+ pos = -1; line = 1; col = 0; charPos = -1;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ wprintf(L"Illegal byte order mark at start of file");
+ exit(1);
+ }
+ Buffer *oldBuf = buffer;
+ buffer = new UTF8Buffer(buffer); col = 0; charPos = -1;
+ delete oldBuf; oldBuf = NULL;
+ NextCh();
+ }
+
+
+ pt = tokens = CreateToken(); // first token is a dummy
+}
+
+void Scanner::NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+ pos = buffer->GetPos();
+ // buffer reads unicode chars, if UTF8 has been detected
+ ch = buffer->Read(); col++; charPos++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
+ if (ch == EOL) { line++; col = 0; }
+ }
+
+}
+
+void Scanner::AddCh() {
+ if (tlen >= tvalLength) {
+ tvalLength *= 2;
+ wchar_t *newBuf = new wchar_t[tvalLength];
+ memcpy(newBuf, tval, tlen*sizeof(wchar_t));
+ delete [] tval;
+ tval = newBuf;
+ }
+ if (ch != Buffer::EoF) {
+ tval[tlen++] = ch;
+ NextCh();
+ }
+}
+
+
+bool Scanner::Comment0() {
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ NextCh();
+ if (ch == L'/') {
+ NextCh();
+ for(;;) {
+ if (ch == 10) {
+ level--;
+ if (level == 0) { oldEols = line - line0; NextCh(); return true; }
+ NextCh();
+ } else if (ch == buffer->EoF) return false;
+ else NextCh();
+ }
+ } else {
+ buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0;
+ }
+ return false;
+}
+
+bool Scanner::Comment1() {
+ int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;
+ NextCh();
+ if (ch == L'*') {
+ NextCh();
+ for(;;) {
+ if (ch == L'*') {
+ NextCh();
+ if (ch == L'/') {
+ level--;
+ if (level == 0) { oldEols = line - line0; NextCh(); return true; }
+ NextCh();
+ }
+ } else if (ch == L'/') {
+ NextCh();
+ if (ch == L'*') {
+ level++; NextCh();
+ }
+ } else if (ch == buffer->EoF) return false;
+ else NextCh();
+ }
+ } else {
+ buffer->SetPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0;
+ }
+ return false;
+}
+
+
+void Scanner::CreateHeapBlock() {
+ void* newHeap;
+ char* cur = (char*) firstHeap;
+
+ while(((char*) tokens < cur) || ((char*) tokens > (cur + COCO_HEAP_BLOCK_SIZE))) {
+ cur = *((char**) (cur + COCO_HEAP_BLOCK_SIZE));
+ free(firstHeap);
+ firstHeap = cur;
+ }
+
+ // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ newHeap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*));
+ *heapEnd = newHeap;
+ heapEnd = (void**) (((char*) newHeap) + COCO_HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heap = newHeap;
+ heapTop = heap;
+}
+
+Token* Scanner::CreateToken() {
+ Token *t;
+ if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
+ CreateHeapBlock();
+ }
+ t = (Token*) heapTop;
+ heapTop = (void*) ((char*) heapTop + sizeof(Token));
+ t->val = NULL;
+ t->next = NULL;
+ return t;
+}
+
+void Scanner::AppendVal(Token *t) {
+ int reqMem = (tlen + 1) * sizeof(wchar_t);
+ if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
+ if (reqMem > COCO_HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too long token value\n");
+ exit(1);
+ }
+ CreateHeapBlock();
+ }
+ t->val = (wchar_t*) heapTop;
+ heapTop = (void*) ((char*) heapTop + reqMem);
+
+ wcsncpy(t->val, tval, tlen);
+ t->val[tlen] = L'\0';
+}
+
+Token* Scanner::NextToken() {
+ while (ch == ' ' ||
+ (ch >= 9 && ch <= 10) || ch == 13
+ ) NextCh();
+ if ((ch == L'/' && Comment0()) || (ch == L'/' && Comment1())) return NextToken();
+ int recKind = noSym;
+ int recEnd = pos;
+ t = CreateToken();
+ t->pos = pos; t->col = col; t->line = line; t->charPos = charPos;
+ int state = start.state(ch);
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t->kind = eofSym; break; } // NextCh already done
+ case 0: {
+ case_0:
+ if (recKind != noSym) {
+ tlen = recEnd - t->pos;
+ SetScannerBehindT();
+ }
+ t->kind = recKind; break;
+ } // NextCh already done
+ case 1:
+ case_1:
+ recEnd = pos; recKind = 1;
+ if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_1;}
+ else {t->kind = 1; wchar_t *literal = coco_string_create(tval, 0, tlen); t->kind = keywords.get(literal, t->kind); coco_string_delete(literal); break;}
+ case 2:
+ case_2:
+ recEnd = pos; recKind = 2;
+ if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_2;}
+ else {t->kind = 2; break;}
+ case 3:
+ case_3:
+ {t->kind = 3; break;}
+ case 4:
+ case_4:
+ {t->kind = 4; break;}
+ case 5:
+ if (ch <= 9 || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= L'&') || (ch >= L'(' && ch <= L'[') || (ch >= L']' && ch <= 65535)) {AddCh(); goto case_6;}
+ else if (ch == 92) {AddCh(); goto case_7;}
+ else {goto case_0;}
+ case 6:
+ case_6:
+ if (ch == 39) {AddCh(); goto case_9;}
+ else {goto case_0;}
+ case 7:
+ case_7:
+ if ((ch >= L' ' && ch <= L'~')) {AddCh(); goto case_8;}
+ else {goto case_0;}
+ case 8:
+ case_8:
+ if ((ch >= L'0' && ch <= L'9') || (ch >= L'a' && ch <= L'f')) {AddCh(); goto case_8;}
+ else if (ch == 39) {AddCh(); goto case_9;}
+ else {goto case_0;}
+ case 9:
+ case_9:
+ {t->kind = 5; break;}
+ case 10:
+ case_10:
+ recEnd = pos; recKind = 42;
+ if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_10;}
+ else {t->kind = 42; break;}
+ case 11:
+ case_11:
+ recEnd = pos; recKind = 43;
+ if ((ch >= L'-' && ch <= L'.') || (ch >= L'0' && ch <= L':') || (ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_11;}
+ else {t->kind = 43; break;}
+ case 12:
+ case_12:
+ if (ch <= 9 || (ch >= 11 && ch <= 12) || (ch >= 14 && ch <= L'!') || (ch >= L'#' && ch <= L'[') || (ch >= L']' && ch <= 65535)) {AddCh(); goto case_12;}
+ else if (ch == 10 || ch == 13) {AddCh(); goto case_4;}
+ else if (ch == L'"') {AddCh(); goto case_3;}
+ else if (ch == 92) {AddCh(); goto case_14;}
+ else {goto case_0;}
+ case 13:
+ recEnd = pos; recKind = 42;
+ if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_10;}
+ else if ((ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_15;}
+ else {t->kind = 42; break;}
+ case 14:
+ case_14:
+ if ((ch >= L' ' && ch <= L'~')) {AddCh(); goto case_12;}
+ else {goto case_0;}
+ case 15:
+ case_15:
+ recEnd = pos; recKind = 42;
+ if ((ch >= L'0' && ch <= L'9')) {AddCh(); goto case_10;}
+ else if ((ch >= L'A' && ch <= L'Z') || ch == L'_' || (ch >= L'a' && ch <= L'z')) {AddCh(); goto case_15;}
+ else if (ch == L'=') {AddCh(); goto case_11;}
+ else {t->kind = 42; break;}
+ case 16:
+ {t->kind = 17; break;}
+ case 17:
+ {t->kind = 20; break;}
+ case 18:
+ {t->kind = 21; break;}
+ case 19:
+ case_19:
+ {t->kind = 22; break;}
+ case 20:
+ {t->kind = 25; break;}
+ case 21:
+ case_21:
+ {t->kind = 26; break;}
+ case 22:
+ case_22:
+ {t->kind = 27; break;}
+ case 23:
+ {t->kind = 28; break;}
+ case 24:
+ {t->kind = 31; break;}
+ case 25:
+ {t->kind = 32; break;}
+ case 26:
+ {t->kind = 33; break;}
+ case 27:
+ {t->kind = 34; break;}
+ case 28:
+ {t->kind = 35; break;}
+ case 29:
+ case_29:
+ {t->kind = 39; break;}
+ case 30:
+ case_30:
+ {t->kind = 40; break;}
+ case 31:
+ recEnd = pos; recKind = 18;
+ if (ch == L'.') {AddCh(); goto case_19;}
+ else if (ch == L'>') {AddCh(); goto case_22;}
+ else if (ch == L')') {AddCh(); goto case_30;}
+ else {t->kind = 18; break;}
+ case 32:
+ recEnd = pos; recKind = 24;
+ if (ch == L'.') {AddCh(); goto case_21;}
+ else {t->kind = 24; break;}
+ case 33:
+ recEnd = pos; recKind = 30;
+ if (ch == L'.') {AddCh(); goto case_29;}
+ else {t->kind = 30; break;}
+
+ }
+ AppendVal(t);
+ return t;
+}
+
+void Scanner::SetScannerBehindT() {
+ buffer->SetPos(t->pos);
+ NextCh();
+ line = t->line; col = t->col; charPos = t->charPos;
+ for (int i = 0; i < tlen; i++) NextCh();
+}
+
+// get the next token (possibly a token already seen during peeking)
+Token* Scanner::Scan() {
+ if (tokens->next == NULL) {
+ return pt = tokens = NextToken();
+ } else {
+ pt = tokens = tokens->next;
+ return tokens;
+ }
+}
+
+// peek for the next token, ignore pragmas
+Token* Scanner::Peek() {
+ do {
+ if (pt->next == NULL) {
+ pt->next = NextToken();
+ }
+ pt = pt->next;
+ } while (pt->kind > maxT); // skip pragmas
+
+ return pt;
+}
+
+// make sure that peeking starts at the current scan position
+void Scanner::ResetPeek() {
+ pt = tokens;
+}
+
+} // namespace
+
diff --git a/old/cococpp/Scanner.frame b/old/cococpp/Scanner.frame
new file mode 100644
index 0000000..db94107
--- /dev/null
+++ b/old/cococpp/Scanner.frame
@@ -0,0 +1,897 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Scanner.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(-->prefixCOCO_SCANNER_H__)
+#define -->prefixCOCO_SCANNER_H__
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// io.h and fcntl are used to ensure binary read from streams on windows
+#if _MSC_VER >= 1300
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if _MSC_VER >= 1400
+#define coco_swprintf swprintf_s
+#elif _MSC_VER >= 1300
+#define coco_swprintf _snwprintf
+#elif defined __MINGW32__
+#define coco_swprintf _snwprintf
+#else
+// assume every other compiler knows swprintf
+#define coco_swprintf swprintf
+#endif
+
+#define COCO_WCHAR_MAX 65535
+#define COCO_MIN_BUFFER_LENGTH 1024
+#define COCO_MAX_BUFFER_LENGTH (64*COCO_MIN_BUFFER_LENGTH)
+#define COCO_HEAP_BLOCK_SIZE (64*1024)
+#define COCO_CPP_NAMESPACE_SEPARATOR L':'
+
+-->namespace_open
+
+// string handling, wide character
+wchar_t* coco_string_create(const wchar_t *value);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length);
+wchar_t* coco_string_create_upper(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen);
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2);
+wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value);
+void coco_string_delete(wchar_t* &data);
+int coco_string_length(const wchar_t* data);
+bool coco_string_endswith(const wchar_t* data, const wchar_t *value);
+int coco_string_indexof(const wchar_t* data, const wchar_t value);
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value);
+void coco_string_merge(wchar_t* &data, const wchar_t* value);
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2);
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2);
+int coco_string_hash(const wchar_t* data);
+
+// string handling, ascii character
+wchar_t* coco_string_create(const char *value);
+char* coco_string_create_char(const wchar_t *value);
+void coco_string_delete(char* &data);
+
+
+class Token
+{
+public:
+ int kind; // token kind
+ int pos; // token position in bytes in the source text (starting at 0)
+ int charPos; // token position in characters in the source text (starting at 0)
+ int col; // token column (starting at 1)
+ int line; // token line (starting at 1)
+ wchar_t* val; // token value
+ Token *next; // ML 2005-03-11 Peek tokens are kept in linked list
+
+ Token();
+ ~Token();
+};
+
+class Buffer {
+// This Buffer supports the following cases:
+// 1) seekable stream (file)
+// a) whole stream in buffer
+// b) part of stream in buffer
+// 2) non seekable stream (network, console)
+private:
+ unsigned char *buf; // input buffer
+ int bufCapacity; // capacity of buf
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ FILE* stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ int ReadNextStreamChunk();
+ bool CanSeek(); // true if stream can be seeked otherwise false
+
+public:
+ static const int EoF = COCO_WCHAR_MAX + 1;
+
+ Buffer(FILE* s, bool isUserStream);
+ Buffer(const unsigned char* buf, int len);
+ Buffer(Buffer *b);
+ virtual ~Buffer();
+
+ virtual void Close();
+ virtual int Read();
+ virtual int Peek();
+ virtual wchar_t* GetString(int beg, int end);
+ virtual int GetPos();
+ virtual void SetPos(int value);
+};
+
+class UTF8Buffer : public Buffer {
+public:
+ UTF8Buffer(Buffer *b) : Buffer(b) {};
+ virtual int Read();
+};
+
+//-----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+//-----------------------------------------------------------------------------------
+class StartStates {
+private:
+ class Elem {
+ public:
+ int key, val;
+ Elem *next;
+ Elem(int key, int val) { this->key = key; this->val = val; next = NULL; }
+ };
+
+ Elem **tab;
+
+public:
+ StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~StartStates() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(int key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = ((unsigned int) key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int state(int key) {
+ Elem *e = tab[((unsigned int) key) % 128];
+ while (e != NULL && e->key != key) e = e->next;
+ return e == NULL ? 0 : e->val;
+ }
+};
+
+//-------------------------------------------------------------------------------------------
+// KeywordMap -- maps strings to integers (identifiers to keyword kinds)
+//-------------------------------------------------------------------------------------------
+class KeywordMap {
+private:
+ class Elem {
+ public:
+ wchar_t *key;
+ int val;
+ Elem *next;
+ Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; }
+ virtual ~Elem() { coco_string_delete(key); }
+ };
+
+ Elem **tab;
+
+public:
+ KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~KeywordMap() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(const wchar_t *key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = coco_string_hash(key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int get(const wchar_t *key, int defaultVal) {
+ Elem *e = tab[coco_string_hash(key) % 128];
+ while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
+ return e == NULL ? defaultVal : e->val;
+ }
+};
+
+class Scanner {
+private:
+ void *firstHeap;
+ void *heap;
+ void *heapTop;
+ void **heapEnd;
+
+ unsigned char EOL;
+ int eofSym;
+ int noSym;
+ int maxT;
+ int charSetSize;
+ StartStates start;
+ KeywordMap keywords;
+
+ Token *t; // current token
+ wchar_t *tval; // text of current token
+ int tvalLength; // length of text of current token
+ int tlen; // length of current token
+
+ Token *tokens; // list of tokens already peeked (first token is a dummy)
+ Token *pt; // current peek token
+
+ int ch; // current input character
+-->casing0
+ int pos; // byte position of current character
+ int charPos; // position by unicode characters starting with 0
+ int line; // line number of current character
+ int col; // column number of current character
+ int oldEols; // EOLs that appeared in a comment;
+
+ void CreateHeapBlock();
+ Token* CreateToken();
+ void AppendVal(Token *t);
+ void SetScannerBehindT();
+
+ void Init();
+ void NextCh();
+ void AddCh();
+-->commentsheader
+ Token* NextToken();
+
+public:
+ Buffer *buffer; // scanner buffer
+
+ Scanner(const unsigned char* buf, int len);
+ Scanner(const wchar_t* fileName);
+ Scanner(FILE* s);
+ ~Scanner();
+ Token* Scan();
+ Token* Peek();
+ void ResetPeek();
+
+}; // end Scanner
+
+-->namespace_close
+
+#endif
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Scanner.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <memory.h>
+#include <string.h>
+#include "Scanner.h"
+
+-->namespace_open
+
+
+// string handling, wide character
+
+
+wchar_t* coco_string_create(const wchar_t* value) {
+ return coco_string_create(value, 0);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex) {
+ int valueLen = 0;
+ int len = 0;
+
+ if (value) {
+ valueLen = wcslen(value);
+ len = valueLen - startIndex;
+ }
+
+ return coco_string_create(value, startIndex, len);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) {
+ int len = 0;
+ wchar_t* data;
+
+ if (value) { len = length; }
+ data = new wchar_t[len + 1];
+ wcsncpy(data, &(value[startIndex]), len);
+ data[len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_upper(const wchar_t* data) {
+ if (!data) { return NULL; }
+
+ int dataLen = 0;
+ if (data) { dataLen = wcslen(data); }
+
+ wchar_t *newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ if ((L'a' <= data[i]) && (data[i] <= L'z')) {
+ newData[i] = data[i] + (L'A' - L'a');
+ }
+ else { newData[i] = data[i]; }
+ }
+
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data) {
+ if (!data) { return NULL; }
+ int dataLen = wcslen(data);
+ return coco_string_create_lower(data, 0, dataLen);
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) {
+ if (!data) { return NULL; }
+
+ wchar_t* newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ wchar_t ch = data[startIndex + i];
+ if ((L'A' <= ch) && (ch <= L'Z')) {
+ newData[i] = ch - (L'A' - L'a');
+ }
+ else { newData[i] = ch; }
+ }
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) {
+ wchar_t* data;
+ int data1Len = 0;
+ int data2Len = 0;
+
+ if (data1) { data1Len = wcslen(data1); }
+ if (data2) {data2Len = wcslen(data2); }
+
+ data = new wchar_t[data1Len + data2Len + 1];
+
+ if (data1) { wcscpy(data, data1); }
+ if (data2) { wcscpy(data + data1Len, data2); }
+
+ data[data1Len + data2Len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) {
+ int targetLen = coco_string_length(target);
+ wchar_t* data = new wchar_t[targetLen + 2];
+ wcsncpy(data, target, targetLen);
+ data[targetLen] = appendix;
+ data[targetLen + 1] = 0;
+ return data;
+}
+
+void coco_string_delete(wchar_t* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+int coco_string_length(const wchar_t* data) {
+ if (data) { return wcslen(data); }
+ return 0;
+}
+
+bool coco_string_endswith(const wchar_t* data, const wchar_t *end) {
+ int dataLen = wcslen(data);
+ int endLen = wcslen(end);
+ return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0);
+}
+
+int coco_string_indexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcschr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcsrchr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+void coco_string_merge(wchar_t* &target, const wchar_t* appendix) {
+ if (!appendix) { return; }
+ wchar_t* data = coco_string_create_append(target, appendix);
+ delete [] target;
+ target = data;
+}
+
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp( data1, data2 ) == 0;
+}
+
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp(data1, data2);
+}
+
+int coco_string_hash(const wchar_t *data) {
+ int h = 0;
+ if (!data) { return 0; }
+ while (*data != 0) {
+ h = (h * 7) ^ *data;
+ ++data;
+ }
+ if (h < 0) { h = -h; }
+ return h;
+}
+
+// string handling, ascii character
+
+wchar_t* coco_string_create(const char* value) {
+ int len = 0;
+ if (value) { len = strlen(value); }
+ wchar_t* data = new wchar_t[len + 1];
+ for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; }
+ data[len] = 0;
+ return data;
+}
+
+char* coco_string_create_char(const wchar_t *value) {
+ int len = coco_string_length(value);
+ char *res = new char[len + 1];
+ for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; }
+ res[len] = 0;
+ return res;
+}
+
+void coco_string_delete(char* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+
+Token::Token() {
+ kind = 0;
+ pos = 0;
+ col = 0;
+ line = 0;
+ val = NULL;
+ next = NULL;
+}
+
+Token::~Token() {
+ coco_string_delete(val);
+}
+
+Buffer::Buffer(FILE* s, bool isUserStream) {
+// ensure binary read on windows
+#if _MSC_VER >= 1300
+ _setmode(_fileno(s), _O_BINARY);
+#endif
+ stream = s; this->isUserStream = isUserStream;
+ if (CanSeek()) {
+ fseek(s, 0, SEEK_END);
+ fileLen = ftell(s);
+ fseek(s, 0, SEEK_SET);
+ bufLen = (fileLen < COCO_MAX_BUFFER_LENGTH) ? fileLen : COCO_MAX_BUFFER_LENGTH;
+ bufStart = INT_MAX; // nothing in the buffer so far
+ } else {
+ fileLen = bufLen = bufStart = 0;
+ }
+ bufCapacity = (bufLen>0) ? bufLen : COCO_MIN_BUFFER_LENGTH;
+ buf = new unsigned char[bufCapacity];
+ if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && CanSeek()) Close();
+}
+
+Buffer::Buffer(Buffer *b) {
+ buf = b->buf;
+ bufCapacity = b->bufCapacity;
+ b->buf = NULL;
+ bufStart = b->bufStart;
+ bufLen = b->bufLen;
+ fileLen = b->fileLen;
+ bufPos = b->bufPos;
+ stream = b->stream;
+ b->stream = NULL;
+ isUserStream = b->isUserStream;
+}
+
+Buffer::Buffer(const unsigned char* buf, int len) {
+ this->buf = new unsigned char[len];
+ memcpy(this->buf, buf, len*sizeof(unsigned char));
+ bufStart = 0;
+ bufCapacity = bufLen = len;
+ fileLen = len;
+ bufPos = 0;
+ stream = NULL;
+}
+
+Buffer::~Buffer() {
+ Close();
+ if (buf != NULL) {
+ delete [] buf;
+ buf = NULL;
+ }
+}
+
+void Buffer::Close() {
+ if (!isUserStream && stream != NULL) {
+ fclose(stream);
+ stream = NULL;
+ }
+}
+
+int Buffer::Read() {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (GetPos() < fileLen) {
+ SetPos(GetPos()); // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
+ return buf[bufPos++];
+ } else {
+ return EoF;
+ }
+}
+
+int Buffer::Peek() {
+ int curPos = GetPos();
+ int ch = Read();
+ SetPos(curPos);
+ return ch;
+}
+
+// beg .. begin, zero-based, inclusive, in byte
+// end .. end, zero-based, exclusive, in byte
+wchar_t* Buffer::GetString(int beg, int end) {
+ int len = 0;
+ wchar_t *buf = new wchar_t[end - beg];
+ int oldPos = GetPos();
+ SetPos(beg);
+ while (GetPos() < end) buf[len++] = (wchar_t) Read();
+ SetPos(oldPos);
+ wchar_t *res = coco_string_create(buf, 0, len);
+ coco_string_delete(buf);
+ return res;
+}
+
+int Buffer::GetPos() {
+ return bufPos + bufStart;
+}
+
+void Buffer::SetPos(int value) {
+ if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while ((value >= fileLen) && (ReadNextStreamChunk() > 0));
+ }
+
+ if ((value < 0) || (value > fileLen)) {
+ wprintf(L"--- buffer out of bounds access, position: %d\n", value);
+ exit(1);
+ }
+
+ if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != NULL) { // must be swapped in
+ fseek(stream, value, SEEK_SET);
+ bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
+ bufStart = value; bufPos = 0;
+ } else {
+ bufPos = fileLen - bufStart; // make Pos return fileLen
+ }
+}
+
+// Read the next chunk of bytes from the stream, increases the buffer
+// if needed and updates the fields fileLen and bufLen.
+// Returns the number of bytes read.
+int Buffer::ReadNextStreamChunk() {
+ int free = bufCapacity - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ bufCapacity = bufLen * 2;
+ unsigned char *newBuf = new unsigned char[bufCapacity];
+ memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
+ delete [] buf;
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = fread(buf + bufLen, sizeof(unsigned char), free, stream);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+}
+
+bool Buffer::CanSeek() {
+ return (stream != NULL) && (ftell(stream) != -1);
+}
+
+int UTF8Buffer::Read() {
+ int ch;
+ do {
+ ch = Buffer::Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
+ if (ch < 128 || ch == EoF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F; ch = Buffer::Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = Buffer::Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+}
+
+Scanner::Scanner(const unsigned char* buf, int len) {
+ buffer = new Buffer(buf, len);
+ Init();
+}
+
+Scanner::Scanner(const wchar_t* fileName) {
+ FILE* stream;
+ char *chFileName = coco_string_create_char(fileName);
+ if ((stream = fopen(chFileName, "rb")) == NULL) {
+ wprintf(L"--- Cannot open file %ls\n", fileName);
+ exit(1);
+ }
+ coco_string_delete(chFileName);
+ buffer = new Buffer(stream, false);
+ Init();
+}
+
+Scanner::Scanner(FILE* s) {
+ buffer = new Buffer(s, true);
+ Init();
+}
+
+Scanner::~Scanner() {
+ char* cur = (char*) firstHeap;
+
+ while(cur != NULL) {
+ cur = *(char**) (cur + COCO_HEAP_BLOCK_SIZE);
+ free(firstHeap);
+ firstHeap = cur;
+ }
+ delete [] tval;
+ delete buffer;
+}
+
+void Scanner::Init() {
+ EOL = '\n';
+ eofSym = 0;
+-->declarations
+
+ tvalLength = 128;
+ tval = new wchar_t[tvalLength]; // text of current token
+
+ // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ heap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*));
+ firstHeap = heap;
+ heapEnd = (void**) (((char*) heap) + COCO_HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heapTop = heap;
+ if (sizeof(Token) > COCO_HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too small COCO_HEAP_BLOCK_SIZE\n");
+ exit(1);
+ }
+
+ pos = -1; line = 1; col = 0; charPos = -1;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ wprintf(L"Illegal byte order mark at start of file");
+ exit(1);
+ }
+ Buffer *oldBuf = buffer;
+ buffer = new UTF8Buffer(buffer); col = 0; charPos = -1;
+ delete oldBuf; oldBuf = NULL;
+ NextCh();
+ }
+
+-->initialization
+ pt = tokens = CreateToken(); // first token is a dummy
+}
+
+void Scanner::NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+ pos = buffer->GetPos();
+ // buffer reads unicode chars, if UTF8 has been detected
+ ch = buffer->Read(); col++; charPos++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
+ if (ch == EOL) { line++; col = 0; }
+ }
+-->casing1
+}
+
+void Scanner::AddCh() {
+ if (tlen >= tvalLength) {
+ tvalLength *= 2;
+ wchar_t *newBuf = new wchar_t[tvalLength];
+ memcpy(newBuf, tval, tlen*sizeof(wchar_t));
+ delete [] tval;
+ tval = newBuf;
+ }
+ if (ch != Buffer::EoF) {
+-->casing2
+ NextCh();
+ }
+}
+
+-->comments
+
+void Scanner::CreateHeapBlock() {
+ void* newHeap;
+ char* cur = (char*) firstHeap;
+
+ while(((char*) tokens < cur) || ((char*) tokens > (cur + COCO_HEAP_BLOCK_SIZE))) {
+ cur = *((char**) (cur + COCO_HEAP_BLOCK_SIZE));
+ free(firstHeap);
+ firstHeap = cur;
+ }
+
+ // COCO_HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ newHeap = malloc(COCO_HEAP_BLOCK_SIZE + sizeof(void*));
+ *heapEnd = newHeap;
+ heapEnd = (void**) (((char*) newHeap) + COCO_HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heap = newHeap;
+ heapTop = heap;
+}
+
+Token* Scanner::CreateToken() {
+ Token *t;
+ if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
+ CreateHeapBlock();
+ }
+ t = (Token*) heapTop;
+ heapTop = (void*) ((char*) heapTop + sizeof(Token));
+ t->val = NULL;
+ t->next = NULL;
+ return t;
+}
+
+void Scanner::AppendVal(Token *t) {
+ int reqMem = (tlen + 1) * sizeof(wchar_t);
+ if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
+ if (reqMem > COCO_HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too long token value\n");
+ exit(1);
+ }
+ CreateHeapBlock();
+ }
+ t->val = (wchar_t*) heapTop;
+ heapTop = (void*) ((char*) heapTop + reqMem);
+
+ wcsncpy(t->val, tval, tlen);
+ t->val[tlen] = L'\0';
+}
+
+Token* Scanner::NextToken() {
+ while (ch == ' ' ||
+-->scan1
+ ) NextCh();
+-->scan2
+ int recKind = noSym;
+ int recEnd = pos;
+ t = CreateToken();
+ t->pos = pos; t->col = col; t->line = line; t->charPos = charPos;
+ int state = start.state(ch);
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t->kind = eofSym; break; } // NextCh already done
+ case 0: {
+ case_0:
+ if (recKind != noSym) {
+ tlen = recEnd - t->pos;
+ SetScannerBehindT();
+ }
+ t->kind = recKind; break;
+ } // NextCh already done
+-->scan3
+ }
+ AppendVal(t);
+ return t;
+}
+
+void Scanner::SetScannerBehindT() {
+ buffer->SetPos(t->pos);
+ NextCh();
+ line = t->line; col = t->col; charPos = t->charPos;
+ for (int i = 0; i < tlen; i++) NextCh();
+}
+
+// get the next token (possibly a token already seen during peeking)
+Token* Scanner::Scan() {
+ if (tokens->next == NULL) {
+ return pt = tokens = NextToken();
+ } else {
+ pt = tokens = tokens->next;
+ return tokens;
+ }
+}
+
+// peek for the next token, ignore pragmas
+Token* Scanner::Peek() {
+ do {
+ if (pt->next == NULL) {
+ pt->next = NextToken();
+ }
+ pt = pt->next;
+ } while (pt->kind > maxT); // skip pragmas
+
+ return pt;
+}
+
+// make sure that peeking starts at the current scan position
+void Scanner::ResetPeek() {
+ pt = tokens;
+}
+
+-->namespace_close
diff --git a/old/cococpp/Scanner.h b/old/cococpp/Scanner.h
new file mode 100644
index 0000000..00b4683
--- /dev/null
+++ b/old/cococpp/Scanner.h
@@ -0,0 +1,291 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+
+#if !defined(Coco_COCO_SCANNER_H__)
+#define Coco_COCO_SCANNER_H__
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// io.h and fcntl are used to ensure binary read from streams on windows
+#if _MSC_VER >= 1300
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if _MSC_VER >= 1400
+#define coco_swprintf swprintf_s
+#elif _MSC_VER >= 1300
+#define coco_swprintf _snwprintf
+#elif defined __MINGW32__
+#define coco_swprintf _snwprintf
+#else
+// assume every other compiler knows swprintf
+#define coco_swprintf swprintf
+#endif
+
+#define COCO_WCHAR_MAX 65535
+#define COCO_MIN_BUFFER_LENGTH 1024
+#define COCO_MAX_BUFFER_LENGTH (64*COCO_MIN_BUFFER_LENGTH)
+#define COCO_HEAP_BLOCK_SIZE (64*1024)
+#define COCO_CPP_NAMESPACE_SEPARATOR L':'
+
+namespace Coco {
+
+
+// string handling, wide character
+wchar_t* coco_string_create(const wchar_t *value);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length);
+wchar_t* coco_string_create_upper(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen);
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2);
+wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value);
+void coco_string_delete(wchar_t* &data);
+int coco_string_length(const wchar_t* data);
+bool coco_string_endswith(const wchar_t* data, const wchar_t *value);
+int coco_string_indexof(const wchar_t* data, const wchar_t value);
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value);
+void coco_string_merge(wchar_t* &data, const wchar_t* value);
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2);
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2);
+int coco_string_hash(const wchar_t* data);
+
+// string handling, ascii character
+wchar_t* coco_string_create(const char *value);
+char* coco_string_create_char(const wchar_t *value);
+void coco_string_delete(char* &data);
+
+
+class Token
+{
+public:
+ int kind; // token kind
+ int pos; // token position in bytes in the source text (starting at 0)
+ int charPos; // token position in characters in the source text (starting at 0)
+ int col; // token column (starting at 1)
+ int line; // token line (starting at 1)
+ wchar_t* val; // token value
+ Token *next; // ML 2005-03-11 Peek tokens are kept in linked list
+
+ Token();
+ ~Token();
+};
+
+class Buffer {
+// This Buffer supports the following cases:
+// 1) seekable stream (file)
+// a) whole stream in buffer
+// b) part of stream in buffer
+// 2) non seekable stream (network, console)
+private:
+ unsigned char *buf; // input buffer
+ int bufCapacity; // capacity of buf
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ FILE* stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ int ReadNextStreamChunk();
+ bool CanSeek(); // true if stream can be seeked otherwise false
+
+public:
+ static const int EoF = COCO_WCHAR_MAX + 1;
+
+ Buffer(FILE* s, bool isUserStream);
+ Buffer(const unsigned char* buf, int len);
+ Buffer(Buffer *b);
+ virtual ~Buffer();
+
+ virtual void Close();
+ virtual int Read();
+ virtual int Peek();
+ virtual wchar_t* GetString(int beg, int end);
+ virtual int GetPos();
+ virtual void SetPos(int value);
+};
+
+class UTF8Buffer : public Buffer {
+public:
+ UTF8Buffer(Buffer *b) : Buffer(b) {};
+ virtual int Read();
+};
+
+//-----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+//-----------------------------------------------------------------------------------
+class StartStates {
+private:
+ class Elem {
+ public:
+ int key, val;
+ Elem *next;
+ Elem(int key, int val) { this->key = key; this->val = val; next = NULL; }
+ };
+
+ Elem **tab;
+
+public:
+ StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~StartStates() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(int key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = ((unsigned int) key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int state(int key) {
+ Elem *e = tab[((unsigned int) key) % 128];
+ while (e != NULL && e->key != key) e = e->next;
+ return e == NULL ? 0 : e->val;
+ }
+};
+
+//-------------------------------------------------------------------------------------------
+// KeywordMap -- maps strings to integers (identifiers to keyword kinds)
+//-------------------------------------------------------------------------------------------
+class KeywordMap {
+private:
+ class Elem {
+ public:
+ wchar_t *key;
+ int val;
+ Elem *next;
+ Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; }
+ virtual ~Elem() { coco_string_delete(key); }
+ };
+
+ Elem **tab;
+
+public:
+ KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~KeywordMap() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(const wchar_t *key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = coco_string_hash(key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int get(const wchar_t *key, int defaultVal) {
+ Elem *e = tab[coco_string_hash(key) % 128];
+ while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
+ return e == NULL ? defaultVal : e->val;
+ }
+};
+
+class Scanner {
+private:
+ void *firstHeap;
+ void *heap;
+ void *heapTop;
+ void **heapEnd;
+
+ unsigned char EOL;
+ int eofSym;
+ int noSym;
+ int maxT;
+ int charSetSize;
+ StartStates start;
+ KeywordMap keywords;
+
+ Token *t; // current token
+ wchar_t *tval; // text of current token
+ int tvalLength; // length of text of current token
+ int tlen; // length of current token
+
+ Token *tokens; // list of tokens already peeked (first token is a dummy)
+ Token *pt; // current peek token
+
+ int ch; // current input character
+
+ int pos; // byte position of current character
+ int charPos; // position by unicode characters starting with 0
+ int line; // line number of current character
+ int col; // column number of current character
+ int oldEols; // EOLs that appeared in a comment;
+
+ void CreateHeapBlock();
+ Token* CreateToken();
+ void AppendVal(Token *t);
+ void SetScannerBehindT();
+
+ void Init();
+ void NextCh();
+ void AddCh();
+ bool Comment0();
+ bool Comment1();
+
+ Token* NextToken();
+
+public:
+ Buffer *buffer; // scanner buffer
+
+ Scanner(const unsigned char* buf, int len);
+ Scanner(const wchar_t* fileName);
+ Scanner(FILE* s);
+ ~Scanner();
+ Token* Scan();
+ Token* Peek();
+ void ResetPeek();
+
+}; // end Scanner
+
+} // namespace
+
+
+#endif
+
diff --git a/old/cococpp/Sets.h b/old/cococpp/Sets.h
new file mode 100644
index 0000000..4acd050
--- /dev/null
+++ b/old/cococpp/Sets.h
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_SETS_H__)
+#define COCO_SETS_H__
+
+#include "BitArray.h"
+
+namespace Coco {
+
+class Sets {
+public:
+ static int First(BitArray *s) {
+ int max = s->getCount();
+ for (int i=0; i<max; i++)
+ if ((*s)[i]) return i;
+ return -1;
+ }
+
+ static int Elements(BitArray *s) {
+ int max = s->getCount();
+ int n = 0;
+ for (int i=0; i<max; i++)
+ if ((*s)[i]) n++;
+ return n;
+ }
+
+ static bool Equals(BitArray *a, BitArray *b) {
+ int max = a->getCount();
+ for (int i=0; i<max; i++)
+ if ((*a)[i] != (*b)[i]) return false;
+ return true;
+ }
+
+ static bool Includes(BitArray *a, BitArray *b) { // a > b ?
+ int max = a->getCount();
+ for (int i=0; i<max; i++)
+ if ((*b)[i] && ! (*a)[i]) return false;
+ return true;
+ }
+
+ static bool Intersect(BitArray *a, BitArray *b) { // a * b != {}
+ int max = a->getCount();
+ for (int i=0; i<max; i++)
+ if ((*a)[i] && (*b)[i]) return true;
+ return false;
+ }
+
+ static void Subtract(BitArray *a, BitArray *b) { // a = a - b
+ BitArray *c = b->Clone();
+ c->Not();
+ a->And(c);
+ delete c;
+ }
+};
+
+}; // namespace
+
+#endif // !defined(COCO_SETS_H__)
diff --git a/old/cococpp/SortedList.cpp b/old/cococpp/SortedList.cpp
new file mode 100644
index 0000000..656100e
--- /dev/null
+++ b/old/cococpp/SortedList.cpp
@@ -0,0 +1,141 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include "SortedList.h"
+#include "Tab.h"
+
+namespace Coco {
+
+int Compare(Symbol *x, Symbol *y) {
+ return coco_string_compareto(x->name, y->name);
+}
+
+SortedEntry::SortedEntry(Symbol* Key, void* Value) {
+ this->Key = Key;
+ this->Value = Value;
+ this->next = NULL;
+}
+
+SortedEntry::~SortedEntry() {
+};
+
+SortedList::SortedList() {
+ Count = 0;
+ Data = NULL;
+}
+
+SortedList::~SortedList() {
+}
+
+bool SortedList::Find(Symbol* key) {
+ SortedEntry* pSortedEntry = Data;
+ while (pSortedEntry) {
+ if (!Compare(pSortedEntry->Key, key))
+ return true;
+ pSortedEntry = pSortedEntry->next;
+ }
+ return false;
+}
+
+void SortedList::Set(Symbol *key, void *value) {
+ if (!Find(key)) {
+ // new entry
+ SortedEntry* pSortedEntry = Data;
+ SortedEntry* pSortedEntryPrev = NULL;
+ SortedEntry* newSortedEntry = new SortedEntry(key, value);
+ if (pSortedEntry) {
+ // insert
+
+ if (Compare(pSortedEntry->Key, key) > 0) { // before the first
+ newSortedEntry->next = Data;
+ Data = newSortedEntry;
+ } else {
+ while (pSortedEntry) {
+ if (Compare(pSortedEntry->Key, key) < 0) {
+ pSortedEntryPrev = pSortedEntry;
+ pSortedEntry = pSortedEntry->next;
+ } else {
+ break;
+ }
+ }
+ pSortedEntryPrev->next = newSortedEntry;
+ newSortedEntry->next = pSortedEntry;
+ }
+ } else {
+ Data = newSortedEntry; // first entry
+ }
+ Count++;
+ } else {
+ // exist entry - overwrite
+ SortedEntry* pSortedEntry = Data;
+ while (Compare(pSortedEntry->Key, key)) {
+ pSortedEntry = pSortedEntry->next;
+ }
+ pSortedEntry->Value = value;
+ }
+}
+
+void* SortedList::Get( Symbol* key ) const // Value
+{
+ SortedEntry* pSortedEntry = Data;
+ while (pSortedEntry) {
+ if (!Compare(pSortedEntry->Key, key))
+ return pSortedEntry->Value;
+ pSortedEntry = pSortedEntry->next;
+ }
+ return NULL;
+}
+
+
+void* SortedList::GetKey( int index ) const // Key
+{
+ if (0 <= index && index < Count) {
+ SortedEntry* pSortedEntry = Data;
+ for (int i=0; i<index; i++) {
+ pSortedEntry = pSortedEntry->next;
+ }
+ return pSortedEntry->Key;
+ } else {
+ return NULL;
+ }
+}
+
+SortedEntry* SortedList::operator[]( int index ) const {
+ if (0 <= index && index < Count) {
+ SortedEntry* pSortedEntry = Data;
+ for (int i=0; i<index; i++) {
+ pSortedEntry = pSortedEntry->next;
+ }
+ return pSortedEntry;
+ } else {
+ return NULL;
+ }
+}
+
+}; // namespace
diff --git a/old/cococpp/SortedList.h b/old/cococpp/SortedList.h
new file mode 100644
index 0000000..5939675
--- /dev/null
+++ b/old/cococpp/SortedList.h
@@ -0,0 +1,68 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_SORTEDLIST_H__)
+#define COCO_SORTEDLIST_H__
+
+namespace Coco {
+
+class Symbol;
+
+class SortedEntry
+{
+public:
+ Symbol* Key;
+ void* Value;
+ SortedEntry* next;
+
+ SortedEntry(Symbol* Key, void* Value);
+ virtual ~SortedEntry();
+};
+
+class SortedList
+{
+public:
+ SortedList();
+ virtual ~SortedList();
+
+ void Set(Symbol *key, void *value);
+ void* Get( Symbol* key ) const; // Value
+ void* GetKey( int index ) const ;// Key
+ SortedEntry* operator[]( int index ) const;
+
+ int Count;
+private:
+ bool Find(Symbol* key);
+
+ SortedEntry *Data;
+
+};
+
+}; // namespace
+
+#endif // !defined(COCO_SORTEDLIST_H__)
diff --git a/old/cococpp/State.cpp b/old/cococpp/State.cpp
new file mode 100644
index 0000000..1f7eeb6
--- /dev/null
+++ b/old/cococpp/State.cpp
@@ -0,0 +1,77 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Action.h"
+#include "State.h"
+
+namespace Coco {
+
+State::State() {
+ this->firstAction = NULL;
+ this->endOf = NULL;
+ this->ctx = false;
+ this->next = NULL;
+}
+
+void State::AddAction(Action *act) {
+ Action *lasta = NULL, *a = firstAction;
+ while (a != NULL && act->typ >= a->typ) {lasta = a; a = a->next;}
+ // collecting classes at the beginning gives better performance
+ act->next = a;
+ if (a==firstAction) {
+ firstAction = act;
+ }
+ else {
+ lasta->next = act;
+ }
+}
+
+void State::DetachAction(Action *act) {
+ Action *lasta = NULL, *a = firstAction;
+ while (a != NULL && a != act) {lasta = a; a = a->next;}
+ if (a != NULL) {
+ if (a == firstAction) {
+ firstAction = a->next;
+ }
+ else {
+ lasta->next = a->next;
+ }
+ }
+}
+
+
+void State::MeltWith(State *s) { // copy actions of s to state
+ Action *a;
+ for (Action *action = s->firstAction; action != NULL; action = action->next) {
+ a = new Action(action->typ, action->sym, action->tc);
+ a->AddTargets(action);
+ AddAction(a);
+ }
+}
+
+}; // namespace
diff --git a/old/cococpp/State.h b/old/cococpp/State.h
new file mode 100644
index 0000000..318d77a
--- /dev/null
+++ b/old/cococpp/State.h
@@ -0,0 +1,55 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_STATE_H__)
+#define COCO_STATE_H__
+
+#include "Symbol.h"
+
+namespace Coco {
+
+class Action;
+
+class State // state of finite automaton
+{
+public:
+ int nr; // state number
+ Action *firstAction; // to first action of this state
+ Symbol *endOf; // recognized token if state is final
+ bool ctx; // true if state is reached via contextTrans
+ State *next;
+
+ State();
+ void AddAction(Action *act);
+ void DetachAction(Action *act);
+ void MeltWith(State *s);
+};
+
+}; // namespace
+
+#endif // !defined(COCO_STATE_H__)
diff --git a/old/cococpp/StringBuilder.cpp b/old/cococpp/StringBuilder.cpp
new file mode 100644
index 0000000..a9cf4b4
--- /dev/null
+++ b/old/cococpp/StringBuilder.cpp
@@ -0,0 +1,88 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <string.h>
+#include "StringBuilder.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+void StringBuilder::Init(int capacity) {
+ length = 0;
+ this->capacity = capacity;
+ data = new wchar_t[capacity + 1];
+ data[0] = 0;
+}
+
+StringBuilder::StringBuilder(int capacity) {
+ Init(capacity);
+}
+
+StringBuilder::StringBuilder(const wchar_t *val) {
+ capacity = length = wcslen(val);
+ Init(capacity);
+ wcscpy(data, val);
+}
+
+StringBuilder::~StringBuilder() {
+ if (data != NULL) {
+ delete [] data;
+ data = NULL;
+ length = 0;
+ capacity = 0;
+ }
+}
+
+void StringBuilder::Append(const wchar_t value) {
+ if (length == capacity) {
+ int oldCap = capacity;
+ capacity = capacity * 2;
+ wchar_t *nData = new wchar_t[capacity + 1];
+ memcpy(nData, data, oldCap * sizeof(int));
+ delete [] data;
+ data = nData;
+ }
+
+ data[length] = value;
+ length++;
+ data[length] = '\0';
+}
+
+void StringBuilder::Append(const wchar_t *value) {
+ if (length + (int)wcslen(value) < capacity) {
+ wcscpy(data + length, value);
+ length += wcslen(value);
+ }
+}
+
+
+wchar_t* StringBuilder::ToString() {
+ return coco_string_create(data);
+}
+
+}; // namespace
diff --git a/old/cococpp/StringBuilder.h b/old/cococpp/StringBuilder.h
new file mode 100644
index 0000000..35c8cd4
--- /dev/null
+++ b/old/cococpp/StringBuilder.h
@@ -0,0 +1,29 @@
+#if !defined(COCO_STRINGBUILDER_H__)
+#define COCO_STRINGBUILDER_H__
+
+#include<stddef.h>
+
+namespace Coco {
+
+class StringBuilder
+{
+public:
+ StringBuilder(int capacity = 32);
+ StringBuilder(const wchar_t *val);
+
+ virtual ~StringBuilder();
+ void Append(const wchar_t val);
+ void Append(const wchar_t *val);
+ wchar_t* ToString();
+ int GetLength() { return length; };
+
+private:
+ void Init(int capacity);
+ wchar_t *data;
+ int capacity;
+ int length;
+};
+
+}; // namespace
+
+#endif // !defined(COCO_STRINGBUILDER_H__)
diff --git a/old/cococpp/Symbol.cpp b/old/cococpp/Symbol.cpp
new file mode 100644
index 0000000..a340d99
--- /dev/null
+++ b/old/cococpp/Symbol.cpp
@@ -0,0 +1,61 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include "Symbol.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+int Symbol::fixedToken = 0;
+int Symbol::classToken = 1;
+int Symbol::litToken = 2;
+int Symbol::classLitToken = 3;
+
+
+Symbol::Symbol(int typ, const wchar_t* name, int line) {
+ n = 0;
+ graph = NULL;
+ tokenKind = 0;
+ deletable = false;
+ firstReady = false;
+ first = NULL;
+ follow = NULL;
+ nts = NULL;
+ attrPos = NULL;
+ semPos = NULL;
+
+ this->typ = typ;
+ this->name = coco_string_create(name);
+ this->line = line;
+}
+
+Symbol::~Symbol() {
+ coco_string_delete(name);
+}
+
+}; // namespace
diff --git a/old/cococpp/Symbol.h b/old/cococpp/Symbol.h
new file mode 100644
index 0000000..63cb8e8
--- /dev/null
+++ b/old/cococpp/Symbol.h
@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_SYMBOL_H__)
+#define COCO_SYMBOL_H__
+
+#include "Position.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+class Node;
+class BitArray;
+
+class Symbol {
+public:
+ // token kinds
+ static int fixedToken; // e.g. 'a' ('b' | 'c') (structure of literals)
+ static int classToken; // e.g. digit {digit} (at least one char class)
+ static int litToken; // e.g. "while"
+ static int classLitToken; // e.g. letter {letter} but without literals that have the same structure*/
+
+ int n; // symbol number
+ int typ; // t, nt, pr, unknown, rslv /* ML 29_11_2002 slv added */ /* AW slv --> rslv */
+ wchar_t *name; // symbol name
+ Node *graph; // nt: to first node of syntax graph
+ int tokenKind; // t: token kind (fixedToken, classToken, ...)
+ bool deletable; // nt: true if nonterminal is deletable
+ bool firstReady; // nt: true if terminal start symbols have already been computed
+ BitArray *first; // nt: terminal start symbols
+ BitArray *follow; // nt: terminal followers
+ BitArray *nts; // nt: nonterminals whose followers have to be added to this sym
+ int line; // source text line number of item in this node
+ Position *attrPos; // nt: position of attributes in source text (or null)
+ Position *semPos; // pr: pos of semantic action in source text (or null)
+ // nt: pos of local declarations in source text (or null)
+
+
+ Symbol(int typ, const wchar_t* name, int line);
+ virtual ~Symbol();
+};
+
+}; // namespace
+
+#endif // !defined(COCO_SYMBOL_H__)
diff --git a/old/cococpp/Tab.cpp b/old/cococpp/Tab.cpp
new file mode 100644
index 0000000..731ec12
--- /dev/null
+++ b/old/cococpp/Tab.cpp
@@ -0,0 +1,1248 @@
+/*-------------------------------------------------------------------------
+Tab -- Symbol Table Management
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <wchar.h>
+#include "Tab.h"
+#include "Parser.h"
+#include "BitArray.h"
+#include "Scanner.h"
+
+namespace Coco {
+
+const char* Tab::nTyp[] =
+ {" ", "t ", "pr ", "nt ", "clas", "chr ", "wt ", "any ", "eps ",
+ "sync", "sem ", "alt ", "iter", "opt ", "rslv"};
+
+const char* Tab::tKind[] = {"fixedToken", "classToken", "litToken", "classLitToken"};
+
+Tab::Tab(Parser *parser) {
+ for (int i=0; i<10; i++) ddt[i] = false;
+
+ terminals = new ArrayList();
+ pragmas = new ArrayList();
+ nonterminals = new ArrayList();
+ nodes = new ArrayList();
+ dummyNode = NULL;
+ classes= new ArrayList();
+ dummyName = 'A';
+
+ this->parser = parser;
+ trace = parser->trace;
+ errors = parser->errors;
+ eofSy = NewSym(Node::t, L"EOF", 0);
+ dummyNode = NewNode(Node::eps, (Symbol*)NULL, 0);
+ literals = new HashTable();
+ checkEOF = true;
+}
+
+
+Symbol* Tab::NewSym(int typ, const wchar_t* name, int line) {
+ if (coco_string_length(name) == 2 && name[0] == '"') {
+ parser->SemErr(L"empty token not allowed");
+ name = coco_string_create(L"???");
+ }
+ Symbol *sym = new Symbol(typ, name, line);
+
+ if (typ == Node::t) {
+ sym->n = terminals->Count; terminals->Add(sym);
+ } else if (typ == Node::pr) {
+ pragmas->Add(sym);
+ } else if (typ == Node::nt) {
+ sym->n = nonterminals->Count; nonterminals->Add(sym);
+ }
+
+ return sym;
+}
+
+Symbol* Tab::FindSym(const wchar_t* name) {
+ Symbol *s;
+ int i;
+ for (i=0; i<terminals->Count; i++) {
+ s = (Symbol*)((*terminals)[i]);
+ if (coco_string_equal(s->name, name)) return s;
+ }
+ for (i=0; i<nonterminals->Count; i++) {
+ s = (Symbol*)((*nonterminals)[i]);
+ if (coco_string_equal(s->name, name)) return s;
+ }
+ return NULL;
+}
+
+int Tab::Num(Node *p) {
+ if (p == NULL) return 0; else return p->n;
+}
+
+void Tab::PrintSym(Symbol *sym) {
+ wchar_t *paddedName = Name(sym->name);
+ fwprintf(trace, L"%3d %14s %ls", sym->n, paddedName, nTyp[sym->typ]);
+ coco_string_delete(paddedName);
+
+ if (sym->attrPos==NULL) fwprintf(trace, L" false "); else fwprintf(trace, L" true ");
+ if (sym->typ == Node::nt) {
+ fwprintf(trace, L"%5d", Num(sym->graph));
+ if (sym->deletable) fwprintf(trace, L" true "); else fwprintf(trace, L" false ");
+ } else
+ fwprintf(trace, L" ");
+
+ fwprintf(trace, L"%5d %ls\n", sym->line, tKind[sym->tokenKind]);
+}
+
+void Tab::PrintSymbolTable() {
+ fwprintf(trace, L"Symbol Table:\n");
+ fwprintf(trace, L"------------\n\n");
+ fwprintf(trace, L" nr name typ hasAt graph del line tokenKind\n");
+
+ Symbol *sym;
+ int i;
+ for (i=0; i<terminals->Count; i++) {
+ sym = (Symbol*)((*terminals)[i]);
+ PrintSym(sym);
+ }
+ for (i=0; i<pragmas->Count; i++) {
+ sym = (Symbol*)((*pragmas)[i]);
+ PrintSym(sym);
+ }
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ PrintSym(sym);
+ }
+
+
+ fwprintf(trace, L"\nLiteral Tokens:\n");
+ fwprintf(trace, L"--------------\n");
+
+ Iterator *iter = literals->GetIterator();
+ while (iter->HasNext()) {
+ DictionaryEntry *e = iter->Next();
+ fwprintf(trace, L"_%ls = %ls.\n", ((Symbol*) (e->val))->name, e->key);
+ }
+ fwprintf(trace, L"\n");
+}
+
+void Tab::PrintSet(BitArray *s, int indent) {
+ int col, len;
+ col = indent;
+ Symbol *sym;
+ for (int i=0; i<terminals->Count; i++) {
+ sym = (Symbol*)((*terminals)[i]);
+ if ((*s)[sym->n]) {
+ len = coco_string_length(sym->name);
+ if (col + len >= 80) {
+ fwprintf(trace, L"\n");
+ for (col = 1; col < indent; col++) fwprintf(trace, L" ");
+ }
+ fwprintf(trace, L"%ls ", sym->name);
+ col += len + 1;
+ }
+ }
+ if (col == indent) fwprintf(trace, L"-- empty set --");
+ fwprintf(trace, L"\n");
+}
+
+//---------------------------------------------------------------------
+// Syntax graph management
+//---------------------------------------------------------------------
+
+Node* Tab::NewNode(int typ, Symbol *sym, int line) {
+ Node* node = new Node(typ, sym, line);
+ node->n = nodes->Count;
+ nodes->Add(node);
+ return node;
+}
+
+
+Node* Tab::NewNode(int typ, Node* sub) {
+ Node* node = NewNode(typ, (Symbol*)NULL, 0);
+ node->sub = sub;
+ return node;
+}
+
+Node* Tab::NewNode(int typ, int val, int line) {
+ Node* node = NewNode(typ, (Symbol*)NULL, line);
+ node->val = val;
+ return node;
+}
+
+
+void Tab::MakeFirstAlt(Graph *g) {
+ g->l = NewNode(Node::alt, g->l); g->l->line = g->l->sub->line;
+ g->r->up = true;
+ g->l->next = g->r;
+ g->r = g->l;
+}
+
+// The result will be in g1
+void Tab::MakeAlternative(Graph *g1, Graph *g2) {
+ g2->l = NewNode(Node::alt, g2->l); g2->l->line = g2->l->sub->line;
+ g2->l->up = true;
+ g2->r->up = true;
+ 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;
+ // append alternative to g1 end list
+ p->next = g2->l;
+ // append g2 end list to g1 end list
+ g2->l->next = g2->r;
+}
+
+// The result will be in g1
+void Tab::MakeSequence(Graph *g1, Graph *g2) {
+ 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 = q;
+ }
+ g1->r = g2->r;
+}
+
+void Tab::MakeIteration(Graph *g) {
+ g->l = NewNode(Node::iter, g->l);
+ g->r->up = true;
+ Node *p = g->r;
+ g->r = g->l;
+ while (p != NULL) {
+ Node *q = p->next; p->next = g->l;
+ p = q;
+ }
+}
+
+void Tab::MakeOption(Graph *g) {
+ g->l = NewNode(Node::opt, g->l);
+ g->r->up = true;
+ g->l->next = g->r;
+ g->r = g->l;
+}
+
+void Tab::Finish(Graph *g) {
+ Node *p = g->r;
+ while (p != NULL) {
+ Node *q = p->next; p->next = NULL;
+ p = q;
+ }
+}
+
+void Tab::DeleteNodes() {
+ nodes = new ArrayList();
+ dummyNode = NewNode(Node::eps, (Symbol*)NULL, 0);
+}
+
+Graph* Tab::StrToGraph(const wchar_t* str) {
+ wchar_t *subStr = coco_string_create(str, 1, coco_string_length(str)-2);
+ wchar_t *s = Unescape(subStr);
+ coco_string_delete(subStr);
+ if (coco_string_length(s) == 0) parser->SemErr(L"empty token not allowed");
+ Graph *g = new Graph();
+ g->r = dummyNode;
+ for (int i = 0; i < coco_string_length(s); i++) {
+ Node *p = NewNode(Node::chr, (int)s[i], 0);
+ g->r->next = p; g->r = p;
+ }
+ g->l = dummyNode->next; dummyNode->next = NULL;
+ coco_string_delete(s);
+ return g;
+}
+
+
+void Tab::SetContextTrans(Node *p) { // set transition code in the graph rooted at p
+ while (p != NULL) {
+ if (p->typ == Node::chr || p->typ == Node::clas) {
+ p->code = Node::contextTrans;
+ } else if (p->typ == Node::opt || p->typ == Node::iter) {
+ SetContextTrans(p->sub);
+ } else if (p->typ == Node::alt) {
+ SetContextTrans(p->sub); SetContextTrans(p->down);
+ }
+ if (p->up) break;
+ p = p->next;
+ }
+}
+
+//------------ graph deletability check -----------------
+
+bool Tab::DelGraph(Node* p) {
+ return p == NULL || (DelNode(p) && DelGraph(p->next));
+}
+
+bool Tab::DelSubGraph(Node* p) {
+ return p == NULL || (DelNode(p) && (p->up || DelSubGraph(p->next)));
+}
+
+bool Tab::DelNode(Node* p) {
+ if (p->typ == Node::nt) {
+ return p->sym->deletable;
+ }
+ else if (p->typ == Node::alt) {
+ return DelSubGraph(p->sub) || (p->down != NULL && DelSubGraph(p->down));
+ }
+ else {
+ return p->typ == Node::iter || p->typ == Node::opt || p->typ == Node::sem
+ || p->typ == Node::eps || p->typ == Node::rslv || p->typ == Node::sync;
+ }
+}
+
+//----------------- graph printing ----------------------
+
+int Tab::Ptr(Node *p, bool up) {
+ if (p == NULL) return 0;
+ else if (up) return -(p->n);
+ else return p->n;
+}
+
+wchar_t* Tab::Pos(Position *pos) {
+ wchar_t* format = new wchar_t[10];
+ if (pos == NULL) {
+ coco_swprintf(format, 10, L" ");
+ } else {
+ coco_swprintf(format, 10, L"%5d", pos->beg);
+ }
+ return format;
+}
+
+wchar_t* Tab::Name(const wchar_t *name) {
+ wchar_t *name2 = coco_string_create_append(name, L" ");
+ wchar_t *subName2 = coco_string_create(name2, 0, 12);
+ coco_string_delete(name2);
+ return subName2;
+ // found no simpler way to get the first 12 characters of the name
+ // padded with blanks on the right
+}
+
+void Tab::PrintNodes() {
+ fwprintf(trace, L"Graph nodes:\n");
+ fwprintf(trace, L"----------------------------------------------------\n");
+ fwprintf(trace, L" n type name next down sub pos line\n");
+ fwprintf(trace, L" val code\n");
+ fwprintf(trace, L"----------------------------------------------------\n");
+
+ Node *p;
+ for (int i=0; i<nodes->Count; i++) {
+ p = (Node*)((*nodes)[i]);
+ fwprintf(trace, L"%4d %ls ", p->n, (nTyp[p->typ]));
+ if (p->sym != NULL) {
+ wchar_t *paddedName = Name(p->sym->name);
+ fwprintf(trace, L"%12s ", paddedName);
+ coco_string_delete(paddedName);
+ } else if (p->typ == Node::clas) {
+ CharClass *c = (CharClass*)(*classes)[p->val];
+ wchar_t *paddedName = Name(c->name);
+ fwprintf(trace, L"%12s ", paddedName);
+ coco_string_delete(paddedName);
+ } else fwprintf(trace, L" ");
+ fwprintf(trace, L"%5d ", Ptr(p->next, p->up));
+
+ if (p->typ == Node::t || p->typ == Node::nt || p->typ == Node::wt) {
+ fwprintf(trace, L" %5s", Pos(p->pos));
+ } if (p->typ == Node::chr) {
+ fwprintf(trace, L"%5d %5d ", p->val, p->code);
+ } if (p->typ == Node::clas) {
+ fwprintf(trace, L" %5d ", p->code);
+ } if (p->typ == Node::alt || p->typ == Node::iter || p->typ == Node::opt) {
+ fwprintf(trace, L"%5d %5d ", Ptr(p->down, false), Ptr(p->sub, false));
+ } if (p->typ == Node::sem) {
+ fwprintf(trace, L" %5s", Pos(p->pos));
+ } if (p->typ == Node::eps || p->typ == Node::any || p->typ == Node::sync) {
+ fwprintf(trace, L" ");
+ }
+ fwprintf(trace, L"%5d\n", p->line);
+ }
+ fwprintf(trace, L"\n");
+}
+
+//---------------------------------------------------------------------
+// Character class management
+//---------------------------------------------------------------------
+
+
+CharClass* Tab::NewCharClass(const wchar_t* name, CharSet *s) {
+ CharClass *c;
+ if (coco_string_equal(name, L"#")) {
+ wchar_t* temp = coco_string_create_append(name, (wchar_t) dummyName++);
+ c = new CharClass(temp, s);
+ coco_string_delete(temp);
+ } else {
+ c = new CharClass(name, s);
+ }
+ c->n = classes->Count;
+ classes->Add(c);
+ return c;
+}
+
+CharClass* Tab::FindCharClass(const wchar_t* name) {
+ CharClass *c;
+ for (int i=0; i<classes->Count; i++) {
+ c = (CharClass*)((*classes)[i]);
+ if (coco_string_equal(c->name, name)) return c;
+ }
+ return NULL;
+}
+
+CharClass* Tab::FindCharClass(CharSet *s) {
+ CharClass *c;
+ for (int i=0; i<classes->Count; i++) {
+ c = (CharClass*)((*classes)[i]);
+ if (s->Equals(c->set)) return c;
+ }
+ return NULL;
+}
+
+CharSet* Tab::CharClassSet(int i) {
+ return ((CharClass*)((*classes)[i]))->set;
+}
+
+//----------- character class printing
+
+wchar_t* Tab::Ch(const wchar_t ch) {
+ wchar_t* format = new wchar_t[10];
+ if (ch < L' ' || ch >= 127 || ch == L'\'' || ch == L'\\') {
+ coco_swprintf(format, 10, L"%d", ch);
+ return format;
+ } else {
+ coco_swprintf(format, 10, L"'%lc'", ch);
+ return format;
+ }
+}
+
+void Tab::WriteCharSet(CharSet *s) {
+ for (CharSet::Range *r = s->head; r != NULL; r = r->next) {
+ if (r->from < r->to) {
+ wchar_t *from = Ch(r->from);
+ wchar_t *to = Ch(r->to);
+ fwprintf(trace, L"%ls .. %ls ", from, to);
+ delete [] from;
+ delete [] to;
+ }
+ else {
+ wchar_t *from = Ch(r->from);
+ fwprintf(trace, L"%ls ", from);
+ delete [] from;
+ }
+ }
+}
+
+void Tab::WriteCharClasses () {
+ CharClass *c;
+ for (int i=0; i<classes->Count; i++) {
+ c = (CharClass*)((*classes)[i]);
+
+ wchar_t* format2 = coco_string_create_append(c->name, L" ");
+ wchar_t* format = coco_string_create(format2, 0, 10);
+ coco_string_merge(format, L": ");
+ fwprintf(trace, format);
+
+ WriteCharSet(c->set);
+ fwprintf(trace, L"\n");
+ coco_string_delete(format);
+ coco_string_delete(format2);
+ }
+ fwprintf(trace, L"\n");
+}
+
+//---------------------------------------------------------------------
+// Symbol set computations
+//---------------------------------------------------------------------
+
+/* Computes the first set for the given Node. */
+BitArray* Tab::First0(Node *p, BitArray *mark) {
+ BitArray *fs = new BitArray(terminals->Count);
+ while (p != NULL && !((*mark)[p->n])) {
+ mark->Set(p->n, true);
+ if (p->typ == Node::nt) {
+ if (p->sym->firstReady) {
+ fs->Or(p->sym->first);
+ } else {
+ BitArray *fs0 = First0(p->sym->graph, mark);
+ fs->Or(fs0);
+ delete fs0;
+ }
+ }
+ else if (p->typ == Node::t || p->typ == Node::wt) {
+ fs->Set(p->sym->n, true);
+ }
+ else if (p->typ == Node::any) {
+ fs->Or(p->set);
+ }
+ else if (p->typ == Node::alt) {
+ BitArray *fs0 = First0(p->sub, mark);
+ fs->Or(fs0);
+ delete fs0;
+ fs0 = First0(p->down, mark);
+ fs->Or(fs0);
+ delete fs0;
+ }
+ else if (p->typ == Node::iter || p->typ == Node::opt) {
+ BitArray *fs0 = First0(p->sub, mark);
+ fs->Or(fs0);
+ delete fs0;
+ }
+
+ if (!DelNode(p)) break;
+ p = p->next;
+ }
+ return fs;
+}
+
+BitArray* Tab::First(Node *p) {
+ BitArray *mark = new BitArray(nodes->Count);
+ BitArray *fs = First0(p, mark);
+ delete mark;
+ if (ddt[3]) {
+ fwprintf(trace, L"\n");
+ if (p != NULL) fwprintf(trace, L"First: node = %d\n", p->n );
+ else fwprintf(trace, L"First: node = null\n");
+ PrintSet(fs, 0);
+ }
+ return fs;
+}
+
+
+void Tab::CompFirstSets() {
+ Symbol *sym;
+ int i;
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ sym->first = new BitArray(terminals->Count);
+ sym->firstReady = false;
+ }
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ sym->first = First(sym->graph);
+ sym->firstReady = true;
+ }
+}
+
+void Tab::CompFollow(Node *p) {
+ while (p != NULL && !((*visited)[p->n])) {
+ visited->Set(p->n, true);
+ if (p->typ == Node::nt) {
+ BitArray *s = First(p->next);
+ p->sym->follow->Or(s);
+ if (DelGraph(p->next))
+ p->sym->nts->Set(curSy->n, true);
+ } else if (p->typ == Node::opt || p->typ == Node::iter) {
+ CompFollow(p->sub);
+ } else if (p->typ == Node::alt) {
+ CompFollow(p->sub); CompFollow(p->down);
+ }
+ p = p->next;
+ }
+}
+
+void Tab::Complete(Symbol *sym) {
+ if (!((*visited)[sym->n])) {
+ visited->Set(sym->n, true);
+ Symbol *s;
+ for (int i=0; i<nonterminals->Count; i++) {
+ s = (Symbol*)((*nonterminals)[i]);
+ if ((*(sym->nts))[s->n]) {
+ Complete(s);
+ sym->follow->Or(s->follow);
+ if (sym == curSy) sym->nts->Set(s->n, false);
+ }
+ }
+ }
+}
+
+void Tab::CompFollowSets() {
+ Symbol *sym;
+ int i;
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ sym->follow = new BitArray(terminals->Count);
+ sym->nts = new BitArray(nonterminals->Count);
+ }
+ gramSy->follow->Set(eofSy->n, true);
+ visited = new BitArray(nodes->Count);
+ for (i=0; i<nonterminals->Count; i++) { // get direct successors of nonterminals
+ sym = (Symbol*)((*nonterminals)[i]);
+ curSy = sym;
+ CompFollow(sym->graph);
+ }
+
+ for (i=0; i<nonterminals->Count; i++) { // add indirect successors to followers
+ sym = (Symbol*)((*nonterminals)[i]);
+ visited = new BitArray(nonterminals->Count);
+ curSy = sym;
+ Complete(sym);
+ }
+}
+
+Node* Tab::LeadingAny(Node *p) {
+ if (p == NULL) return NULL;
+ Node *a = NULL;
+ if (p->typ == Node::any) a = p;
+ else if (p->typ == Node::alt) {
+ a = LeadingAny(p->sub);
+ if (a == NULL) a = LeadingAny(p->down);
+ }
+ else if (p->typ == Node::opt || p->typ == Node::iter) a = LeadingAny(p->sub);
+ if (a == NULL && DelNode(p) && !p->up) a = LeadingAny(p->next);
+ return a;
+}
+
+void Tab::FindAS(Node *p) { // find ANY sets
+ Node *a;
+ while (p != NULL) {
+ if (p->typ == Node::opt || p->typ == Node::iter) {
+ FindAS(p->sub);
+ a = LeadingAny(p->sub);
+ if (a != NULL) Sets::Subtract(a->set, First(p->next));
+ } else if (p->typ == Node::alt) {
+ BitArray *s1 = new BitArray(terminals->Count);
+ Node *q = p;
+ while (q != NULL) {
+ FindAS(q->sub);
+ a = LeadingAny(q->sub);
+ if (a != NULL) {
+ BitArray *tmp = First(q->down);
+ tmp->Or(s1);
+ Sets::Subtract(a->set, tmp);
+ } else {
+ BitArray *f = First(q->sub);
+ s1->Or(f);
+ delete f;
+ }
+ q = q->down;
+ }
+ }
+
+ // Remove alternative terminals before ANY, in the following
+ // examples a and b must be removed from the ANY set:
+ // [a] ANY, or {a|b} ANY, or [a][b] ANY, or (a|) ANY, or
+ // A = [a]. A ANY
+ if (DelNode(p)) {
+ a = LeadingAny(p->next);
+ if (a != NULL) {
+ Node *q = (p->typ == Node::nt) ? p->sym->graph : p->sub;
+ Sets::Subtract(a->set, First(q));
+ }
+ }
+
+ if (p->up) break;
+ p = p->next;
+ }
+}
+
+void Tab::CompAnySets() {
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ FindAS(sym->graph);
+ }
+}
+
+BitArray* Tab::Expected(Node *p, Symbol *curSy) {
+ BitArray *s = First(p);
+ if (DelGraph(p))
+ s->Or(curSy->follow);
+ return s;
+}
+
+// does not look behind resolvers; only called during LL(1) test and in CheckRes
+BitArray* Tab::Expected0(Node *p, Symbol *curSy) {
+ if (p->typ == Node::rslv) return new BitArray(terminals->Count);
+ else return Expected(p, curSy);
+}
+
+void Tab::CompSync(Node *p) {
+ while (p != NULL && !(visited->Get(p->n))) {
+ visited->Set(p->n, true);
+ if (p->typ == Node::sync) {
+ BitArray *s = Expected(p->next, curSy);
+ s->Set(eofSy->n, true);
+ allSyncSets->Or(s);
+ p->set = s;
+ } else if (p->typ == Node::alt) {
+ CompSync(p->sub); CompSync(p->down);
+ } else if (p->typ == Node::opt || p->typ == Node::iter)
+ CompSync(p->sub);
+ p = p->next;
+ }
+}
+
+void Tab::CompSyncSets() {
+ allSyncSets = new BitArray(terminals->Count);
+ allSyncSets->Set(eofSy->n, true);
+ visited = new BitArray(nodes->Count);
+
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ curSy = sym;
+ CompSync(curSy->graph);
+ }
+}
+
+void Tab::SetupAnys() {
+ Node *p;
+ for (int i=0; i<nodes->Count; i++) {
+ p = (Node*)((*nodes)[i]);
+ if (p->typ == Node::any) {
+ p->set = new BitArray(terminals->Count, true);
+ p->set->Set(eofSy->n, false);
+ }
+ }
+}
+
+void Tab::CompDeletableSymbols() {
+ bool changed;
+ Symbol *sym;
+ int i;
+ do {
+ changed = false;
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (!sym->deletable && sym->graph != NULL && DelGraph(sym->graph)) {
+ sym->deletable = true; changed = true;
+ }
+ }
+ } while (changed);
+
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (sym->deletable)
+ wprintf(L" %ls deletable\n", sym->name);
+ }
+}
+
+void Tab::RenumberPragmas() {
+ int n = terminals->Count;
+ Symbol *sym;
+ for (int i=0; i<pragmas->Count; i++) {
+ sym = (Symbol*)((*pragmas)[i]);
+ sym->n = n++;
+ }
+}
+
+void Tab::CompSymbolSets() {
+ CompDeletableSymbols();
+ CompFirstSets();
+ CompAnySets();
+ CompFollowSets();
+ CompSyncSets();
+ if (ddt[1]) {
+ fwprintf(trace, L"\n");
+ fwprintf(trace, L"First & follow symbols:\n");
+ fwprintf(trace, L"----------------------\n\n");
+
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ fwprintf(trace, L"%ls\n", sym->name);
+ fwprintf(trace, L"first: "); PrintSet(sym->first, 10);
+ fwprintf(trace, L"follow: "); PrintSet(sym->follow, 10);
+ fwprintf(trace, L"\n");
+ }
+ }
+ if (ddt[4]) {
+ fwprintf(trace, L"\n");
+ fwprintf(trace, L"ANY and SYNC sets:\n");
+ fwprintf(trace, L"-----------------\n");
+
+ Node *p;
+ for (int i=0; i<nodes->Count; i++) {
+ p = (Node*)((*nodes)[i]);
+ if (p->typ == Node::any || p->typ == Node::sync) {
+ fwprintf(trace, L"%4d %4s ", p->n, nTyp[p->typ]);
+ PrintSet(p->set, 11);
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// String handling
+//---------------------------------------------------------------------
+
+wchar_t Tab::Hex2Char(const wchar_t* s) {
+ int val = 0;
+ int len = coco_string_length(s);
+ for (int i = 0; i < len; i++) {
+ wchar_t ch = s[i];
+ if ('0' <= ch && ch <= '9') val = 16 * val + (ch - '0');
+ else if ('a' <= ch && ch <= 'f') val = 16 * val + (10 + ch - 'a');
+ else if ('A' <= ch && ch <= 'F') val = 16 * val + (10 + ch - 'A');
+ else parser->SemErr(L"bad escape sequence in string or character");
+ }
+ if (val >= COCO_WCHAR_MAX) {/* pdt */
+ parser->SemErr(L"bad escape sequence in string or character");
+ }
+ return (wchar_t) val;
+}
+
+wchar_t* Tab::Char2Hex(const wchar_t ch) {
+ wchar_t* format = new wchar_t[10];
+ coco_swprintf(format, 10, L"\\0x%04x", ch);
+ return format;
+}
+
+wchar_t* Tab::Unescape (const wchar_t* s) {
+ /* replaces escape sequences in s by their Unicode values. */
+ StringBuilder buf = StringBuilder();
+ int i = 0;
+ int len = coco_string_length(s);
+ while (i < len) {
+ if (s[i] == '\\') {
+ switch (s[i+1]) {
+ case L'\\': buf.Append(L'\\'); i += 2; break;
+ case L'\'': buf.Append(L'\''); i += 2; break;
+ case L'\"': buf.Append(L'\"'); i += 2; break;
+ case L'r': buf.Append(L'\r'); i += 2; break;
+ case L'n': buf.Append(L'\n'); i += 2; break;
+ case L't': buf.Append(L'\t'); i += 2; break;
+ case L'0': buf.Append(L'\0'); i += 2; break;
+ case L'a': buf.Append(L'\a'); i += 2; break;
+ case L'b': buf.Append(L'\b'); i += 2; break;
+ case L'f': buf.Append(L'\f'); i += 2; break;
+ case L'v': buf.Append(L'\v'); i += 2; break;
+ case L'u': case L'x':
+ if (i + 6 <= coco_string_length(s)) {
+ wchar_t *subS = coco_string_create(s, i+2, 4);
+ buf.Append(Hex2Char(subS)); i += 6; break;
+ coco_string_delete(subS);
+ } else {
+ parser->SemErr(L"bad escape sequence in string or character");
+ i = coco_string_length(s); break;
+ }
+ default:
+ parser->SemErr(L"bad escape sequence in string or character");
+ i += 2; break;
+ }
+ } else {
+ buf.Append(s[i]);
+ i++;
+ }
+ }
+
+ return buf.ToString();
+}
+
+
+wchar_t* Tab::Escape (const wchar_t* s) {
+ StringBuilder buf = StringBuilder();
+ wchar_t ch;
+ int len = coco_string_length(s);
+ for (int i=0; i < len; i++) {
+ ch = s[i];
+ switch(ch) {
+ case L'\\': buf.Append(L"\\\\"); break;
+ case L'\'': buf.Append(L"\\'"); break;
+ case L'\"': buf.Append(L"\\\""); break;
+ case L'\t': buf.Append(L"\\t"); break;
+ case L'\r': buf.Append(L"\\r"); break;
+ case L'\n': buf.Append(L"\\n"); break;
+ default:
+ if ((ch < L' ') || (ch > 0x7f)) {
+ wchar_t* res = Char2Hex(ch);
+ buf.Append(res);
+ delete [] res;
+ } else
+ buf.Append(ch);
+ break;
+ }
+ }
+ return buf.ToString();
+}
+
+
+//---------------------------------------------------------------------
+// Grammar checks
+//---------------------------------------------------------------------
+
+bool Tab::GrammarOk() {
+ bool ok = NtsComplete()
+ && AllNtReached()
+ && NoCircularProductions()
+ && AllNtToTerm();
+ if (ok) { CheckResolvers(); CheckLL1(); }
+ return ok;
+}
+
+
+//--------------- check for circular productions ----------------------
+
+void Tab::GetSingles(Node *p, ArrayList *singles) {
+ if (p == NULL) return; // end of graph
+ if (p->typ == Node::nt) {
+ if (p->up || DelGraph(p->next)) singles->Add(p->sym);
+ } else if (p->typ == Node::alt || p->typ == Node::iter || p->typ == Node::opt) {
+ if (p->up || DelGraph(p->next)) {
+ GetSingles(p->sub, singles);
+ if (p->typ == Node::alt) GetSingles(p->down, singles);
+ }
+ }
+ if (!p->up && DelNode(p)) GetSingles(p->next, singles);
+}
+
+bool Tab::NoCircularProductions() {
+ bool ok, changed, onLeftSide, onRightSide;
+ ArrayList *list = new ArrayList();
+
+
+ Symbol *sym;
+ int i;
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ ArrayList *singles = new ArrayList();
+ GetSingles(sym->graph, singles); // get nonterminals s such that sym-->s
+ Symbol *s;
+ for (int j=0; j<singles->Count; j++) {
+ s = (Symbol*)((*singles)[j]);
+ list->Add(new CNode(sym, s));
+ }
+ }
+
+ CNode *n;
+ do {
+ changed = false;
+ for (i = 0; i < list->Count; i++) {
+ n = (CNode*)(*list)[i];
+ onLeftSide = false; onRightSide = false;
+ CNode *m;
+ for (int j=0; j<list->Count; j++) {
+ m = (CNode*)((*list)[j]);
+ if (n->left == m->right) onRightSide = true;
+ if (n->right == m->left) onLeftSide = true;
+ }
+ if (!onLeftSide || !onRightSide) {
+ list->Remove(n); i--; changed = true;
+ }
+ }
+ } while(changed);
+ ok = true;
+
+ for (i=0; i<list->Count; i++) {
+ n = (CNode*)((*list)[i]);
+ ok = false; errors->count++;
+ wprintf(L" %ls --> %ls", n->left->name, n->right->name);
+ }
+ return ok;
+}
+
+
+//--------------- check for LL(1) errors ----------------------
+
+void Tab::LL1Error(int cond, Symbol *sym) {
+ wprintf(L" LL1 warning in %ls: ", curSy->name);
+ if (sym != NULL) wprintf(L"%ls is ", sym->name);
+ switch (cond) {
+ case 1: wprintf(L"start of several alternatives\n"); break;
+ case 2: wprintf(L"start & successor of deletable structure\n"); break;
+ case 3: wprintf(L"an ANY node that matches no symbol\n"); break;
+ case 4: wprintf(L"contents of [...] or {...} must not be deletable\n"); break;
+ }
+}
+
+
+void Tab::CheckOverlap(BitArray *s1, BitArray *s2, int cond) {
+ Symbol *sym;
+ for (int i=0; i<terminals->Count; i++) {
+ sym = (Symbol*)((*terminals)[i]);
+ if ((*s1)[sym->n] && (*s2)[sym->n]) {
+ LL1Error(cond, sym);
+ }
+ }
+}
+
+void Tab::CheckAlts(Node *p) {
+ BitArray *s1, *s2;
+ while (p != NULL) {
+ if (p->typ == Node::alt) {
+ Node *q = p;
+ s1 = new BitArray(terminals->Count);
+ while (q != NULL) { // for all alternatives
+ s2 = Expected0(q->sub, curSy);
+ CheckOverlap(s1, s2, 1);
+ s1->Or(s2);
+ CheckAlts(q->sub);
+ q = q->down;
+ }
+ } else if (p->typ == Node::opt || p->typ == Node::iter) {
+ if (DelSubGraph(p->sub)) LL1Error(4, NULL); // e.g. [[...]]
+ else {
+ s1 = Expected0(p->sub, curSy);
+ s2 = Expected(p->next, curSy);
+ CheckOverlap(s1, s2, 2);
+ }
+ CheckAlts(p->sub);
+ } else if (p->typ == Node::any) {
+ if (Sets::Elements(p->set) == 0) LL1Error(3, NULL);
+ // e.g. {ANY} ANY or [ANY] ANY or ( ANY | ANY )
+ }
+ if (p->up) break;
+ p = p->next;
+ }
+}
+
+void Tab::CheckLL1() {
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ curSy = sym;
+ CheckAlts(curSy->graph);
+ }
+}
+
+//------------- check if resolvers are legal --------------------
+
+void Tab::ResErr(Node *p, const wchar_t* msg) {
+ errors->Warning(p->line, p->pos->col, msg);
+}
+
+void Tab::CheckRes(Node *p, bool rslvAllowed) {
+ while (p != NULL) {
+
+ Node *q;
+ if (p->typ == Node::alt) {
+ BitArray *expected = new BitArray(terminals->Count);
+ for (q = p; q != NULL; q = q->down)
+ expected->Or(Expected0(q->sub, curSy));
+ BitArray *soFar = new BitArray(terminals->Count);
+ for (q = p; q != NULL; q = q->down) {
+ if (q->sub->typ == Node::rslv) {
+ BitArray *fs = Expected(q->sub->next, curSy);
+ if (Sets::Intersect(fs, soFar))
+ ResErr(q->sub, L"Warning: Resolver will never be evaluated. Place it at previous conflicting alternative.");
+ if (!Sets::Intersect(fs, expected))
+ ResErr(q->sub, L"Warning: Misplaced resolver: no LL(1) conflict.");
+ } else soFar->Or(Expected(q->sub, curSy));
+ CheckRes(q->sub, true);
+ }
+ } else if (p->typ == Node::iter || p->typ == Node::opt) {
+ if (p->sub->typ == Node::rslv) {
+ BitArray *fs = First(p->sub->next);
+ BitArray *fsNext = Expected(p->next, curSy);
+ if (!Sets::Intersect(fs, fsNext))
+ ResErr(p->sub, L"Warning: Misplaced resolver: no LL(1) conflict.");
+ }
+ CheckRes(p->sub, true);
+ } else if (p->typ == Node::rslv) {
+ if (!rslvAllowed)
+ ResErr(p, L"Warning: Misplaced resolver: no alternative.");
+ }
+
+ if (p->up) break;
+ p = p->next;
+ rslvAllowed = false;
+ }
+}
+
+void Tab::CheckResolvers() {
+ for (int i=0; i<nonterminals->Count; i++) {
+ curSy = (Symbol*)((*nonterminals)[i]);
+ CheckRes(curSy->graph, false);
+ }
+}
+
+
+//------------- check if every nts has a production --------------------
+
+bool Tab::NtsComplete() {
+ bool complete = true;
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (sym->graph == NULL) {
+ complete = false; errors->count++;
+ wprintf(L" No production for %ls\n", sym->name);
+ }
+ }
+ return complete;
+}
+
+//-------------- check if every nts can be reached -----------------
+
+void Tab::MarkReachedNts(Node *p) {
+ while (p != NULL) {
+ if (p->typ == Node::nt && !((*visited)[p->sym->n])) { // new nt reached
+ visited->Set(p->sym->n, true);
+ MarkReachedNts(p->sym->graph);
+ } else if (p->typ == Node::alt || p->typ == Node::iter || p->typ == Node::opt) {
+ MarkReachedNts(p->sub);
+ if (p->typ == Node::alt) MarkReachedNts(p->down);
+ }
+ if (p->up) break;
+ p = p->next;
+ }
+}
+
+bool Tab::AllNtReached() {
+ bool ok = true;
+ visited = new BitArray(nonterminals->Count);
+ visited->Set(gramSy->n, true);
+ MarkReachedNts(gramSy->graph);
+ Symbol *sym;
+ for (int i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (!((*visited)[sym->n])) {
+ ok = false; errors->count++;
+ wprintf(L" %ls cannot be reached\n", sym->name);
+ }
+ }
+ return ok;
+}
+
+//--------- check if every nts can be derived to terminals ------------
+
+bool Tab::IsTerm(Node *p, BitArray *mark) { // true if graph can be derived to terminals
+ while (p != NULL) {
+ if (p->typ == Node::nt && !((*mark)[p->sym->n])) return false;
+ if (p->typ == Node::alt && !IsTerm(p->sub, mark)
+ && (p->down == NULL || !IsTerm(p->down, mark))) return false;
+ if (p->up) break;
+ p = p->next;
+ }
+ return true;
+}
+
+
+bool Tab::AllNtToTerm() {
+ bool changed, ok = true;
+ BitArray *mark = new BitArray(nonterminals->Count);
+ // a nonterminal is marked if it can be derived to terminal symbols
+ Symbol *sym;
+ int i;
+ do {
+ changed = false;
+
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (!((*mark)[sym->n]) && IsTerm(sym->graph, mark)) {
+ mark->Set(sym->n, true); changed = true;
+ }
+ }
+ } while (changed);
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ if (!((*mark)[sym->n])) {
+ ok = false; errors->count++;
+ wprintf(L" %ls cannot be derived to terminals\n", sym->name);
+ }
+ }
+ return ok;
+}
+
+//---------------------------------------------------------------------
+// Cross reference list
+//---------------------------------------------------------------------
+
+void Tab::XRef() {
+ SortedList *xref = new SortedList();
+ // collect lines where symbols have been defined
+ Symbol *sym;
+ int i, j;
+ for (i=0; i<nonterminals->Count; i++) {
+ sym = (Symbol*)((*nonterminals)[i]);
+ ArrayList *list = (ArrayList*)(xref->Get(sym));
+ if (list == NULL) {list = new ArrayList(); xref->Set(sym, list);}
+ int *intg = new int(- sym->line);
+ list->Add(intg);
+ }
+ // collect lines where symbols have been referenced
+ Node *n;
+ for (i=0; i<nodes->Count; i++) {
+ n = (Node*)((*nodes)[i]);
+ if (n->typ == Node::t || n->typ == Node::wt || n->typ == Node::nt) {
+ ArrayList *list = (ArrayList*)(xref->Get(n->sym));
+ if (list == NULL) {list = new ArrayList(); xref->Set(n->sym, list);}
+ int *intg = new int(n->line);
+ list->Add(intg);
+ }
+ }
+ // print cross reference list
+ fwprintf(trace, L"\n");
+ fwprintf(trace, L"Cross reference list:\n");
+ fwprintf(trace, L"--------------------\n\n");
+
+ for (i=0; i<xref->Count; i++) {
+ sym = (Symbol*)(xref->GetKey(i));
+ wchar_t *paddedName = Name(sym->name);
+ fwprintf(trace, L" %12ls", paddedName);
+ coco_string_delete(paddedName);
+ ArrayList *list = (ArrayList*)(xref->Get(sym));
+ int col = 14;
+ int line;
+ for (j=0; j<list->Count; j++) {
+ line = *(int*)((*list)[j]);
+ if (col + 5 > 80) {
+ fwprintf(trace, L"\n");
+ for (col = 1; col <= 14; col++) fwprintf(trace, L" ");
+ }
+ fwprintf(trace, L"%5d", line); col += 5;
+ }
+ fwprintf(trace, L"\n");
+ }
+ fwprintf(trace, L"\n\n");
+}
+
+void Tab::SetDDT(const wchar_t* s) {
+ wchar_t* st = coco_string_create_upper(s);
+ wchar_t ch;
+ int len = coco_string_length(st);
+ for (int i = 0; i < len; i++) {
+ ch = st[i];
+ if (L'0' <= ch && ch <= L'9') ddt[ch - L'0'] = true;
+ else switch (ch) {
+ case L'A' : ddt[0] = true; break; // trace automaton
+ case L'F' : ddt[1] = true; break; // list first/follow sets
+ case L'G' : ddt[2] = true; break; // print syntax graph
+ case L'I' : ddt[3] = true; break; // trace computation of first sets
+ case L'J' : ddt[4] = true; break; // print ANY and SYNC sets
+ case L'P' : ddt[8] = true; break; // print statistics
+ case L'S' : ddt[6] = true; break; // list symbol table
+ case L'X' : ddt[7] = true; break; // list cross reference table
+ default : break;
+ }
+ }
+ coco_string_delete(st);
+}
+
+
+void Tab::SetOption(const wchar_t* s) {
+ // example: $namespace=xxx
+ // index of '=' is 10 => nameLenght = 10
+ // start index of xxx = 11
+
+ int nameLenght = coco_string_indexof(s, '=');
+ int valueIndex = nameLenght + 1;
+
+ wchar_t *name = coco_string_create(s, 0, nameLenght);
+ wchar_t *value = coco_string_create(s, valueIndex);
+
+ if (coco_string_equal(L"$namespace", name)) {
+ if (nsName == NULL) nsName = coco_string_create(value);
+ } else if (coco_string_equal(L"$checkEOF", name)) {
+ checkEOF = coco_string_equal(L"true", value);
+ }
+
+ delete [] name;
+ delete [] value;
+}
+
+
+}; // namespace
diff --git a/old/cococpp/Tab.h b/old/cococpp/Tab.h
new file mode 100644
index 0000000..ae788aa
--- /dev/null
+++ b/old/cococpp/Tab.h
@@ -0,0 +1,245 @@
+/*-------------------------------------------------------------------------
+Tab -- Symbol Table Management
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_TAB_H__)
+#define COCO_TAB_H__
+
+#include "ArrayList.h"
+#include "HashTable.h"
+#include "StringBuilder.h"
+#include "SortedList.h"
+#include "Scanner.h"
+#include "Position.h"
+#include "Symbol.h"
+#include "Node.h"
+#include "Graph.h"
+#include "Sets.h"
+#include "CharClass.h"
+
+namespace Coco {
+
+class Errors;
+class Parser;
+class BitArray;
+
+class Tab {
+public:
+ Position *semDeclPos; // position of global semantic declarations
+ CharSet *ignored; // characters ignored by the scanner
+ bool ddt[10]; // debug and test switches
+ Symbol *gramSy; // root nonterminal; filled by ATG
+ Symbol *eofSy; // end of file symbol
+ Symbol *noSym; // used in case of an error
+ BitArray *allSyncSets; // union of all synchronisation sets
+ HashTable *literals; // symbols that are used as literals
+
+ wchar_t* srcName; // name of the atg file (including path)
+ wchar_t* srcDir; // directory path of the atg file
+ wchar_t* nsName; // namespace for generated files
+ wchar_t* frameDir; // directory containing the frame files
+ wchar_t* outDir; // directory for generated files
+ bool checkEOF; // should coco generate a check for EOF at
+ // the end of Parser.Parse():
+ bool emitLines; // emit line directives in generated parser
+
+ BitArray *visited; // mark list for graph traversals
+ Symbol *curSy; // current symbol in computation of sets
+
+ Parser *parser; // other Coco objects
+ FILE* trace;
+
+ Errors *errors;
+
+ ArrayList *terminals;
+ ArrayList *pragmas;
+ ArrayList *nonterminals;
+
+
+ ArrayList *nodes;
+ static const char* nTyp[];
+ Node *dummyNode;
+
+ ArrayList *classes;
+ int dummyName;
+
+
+ Tab(Parser *parser);
+
+ //---------------------------------------------------------------------
+ // Symbol list management
+ //---------------------------------------------------------------------
+
+
+ static const char* tKind[];
+
+ Symbol* NewSym(int typ, const wchar_t* name, int line);
+ Symbol* FindSym(const wchar_t* name);
+ int Num(Node *p);
+ void PrintSym(Symbol *sym);
+ void PrintSymbolTable();
+ void PrintSet(BitArray *s, int indent);
+
+ //---------------------------------------------------------------------
+ // Syntax graph management
+ //---------------------------------------------------------------------
+
+ Node* NewNode(int typ, Symbol *sym, int line);
+ Node* NewNode(int typ, Node* sub);
+ Node* NewNode(int typ, int val, int line);
+ void MakeFirstAlt(Graph *g);
+ void MakeAlternative(Graph *g1, Graph *g2);
+ void MakeSequence(Graph *g1, Graph *g2);
+ void MakeIteration(Graph *g);
+ void MakeOption(Graph *g);
+ void Finish(Graph *g);
+ void DeleteNodes();
+ Graph* StrToGraph(const wchar_t* str);
+ void SetContextTrans(Node *p); // set transition code in the graph rooted at p
+
+ //------------ graph deletability check -----------------
+
+ bool DelGraph(Node* p);
+ bool DelSubGraph(Node* p);
+ bool DelNode(Node* p);
+
+ //----------------- graph printing ----------------------
+
+ int Ptr(Node *p, bool up);
+ wchar_t* Pos(Position *pos);
+ wchar_t* Name(const wchar_t* name);
+ void PrintNodes();
+
+ //---------------------------------------------------------------------
+ // Character class management
+ //---------------------------------------------------------------------
+
+ CharClass* NewCharClass(const wchar_t* name, CharSet *s);
+ CharClass* FindCharClass(const wchar_t* name);
+ CharClass* FindCharClass(CharSet *s);
+ CharSet* CharClassSet(int i);
+
+ //----------- character class printing
+
+ wchar_t* Ch(const wchar_t ch);
+ void WriteCharSet(CharSet *s);
+ void WriteCharClasses ();
+
+ //---------------------------------------------------------------------
+ // Symbol set computations
+ //---------------------------------------------------------------------
+
+ /* Computes the first set for the given Node. */
+ BitArray* First0(Node *p, BitArray *mark);
+ BitArray* First(Node *p);
+ void CompFirstSets();
+ void CompFollow(Node *p);
+ void Complete(Symbol *sym);
+ void CompFollowSets();
+ Node* LeadingAny(Node *p);
+ void FindAS(Node *p); // find ANY sets
+ void CompAnySets();
+ BitArray* Expected(Node *p, Symbol *curSy);
+ // does not look behind resolvers; only called during LL(1) test and in CheckRes
+ BitArray* Expected0(Node *p, Symbol *curSy);
+ void CompSync(Node *p);
+ void CompSyncSets();
+ void SetupAnys();
+ void CompDeletableSymbols();
+ void RenumberPragmas();
+ void CompSymbolSets();
+
+ //---------------------------------------------------------------------
+ // String handling
+ //---------------------------------------------------------------------
+
+ wchar_t Hex2Char(const wchar_t* s);
+ wchar_t* Char2Hex(const wchar_t ch);
+ wchar_t* Unescape(const wchar_t* s);
+ wchar_t* Escape(const wchar_t* s);
+
+ //---------------------------------------------------------------------
+ // Grammar checks
+ //---------------------------------------------------------------------
+
+ bool GrammarOk();
+
+ //--------------- check for circular productions ----------------------
+
+ class CNode { // node of list for finding circular productions
+ public:
+ Symbol *left, *right;
+
+ CNode (Symbol *l, Symbol *r) {
+ left = l; right = r;
+ }
+ };
+
+ void GetSingles(Node *p, ArrayList *singles);
+ bool NoCircularProductions();
+
+ //--------------- check for LL(1) errors ----------------------
+
+ void LL1Error(int cond, Symbol *sym);
+ void CheckOverlap(BitArray *s1, BitArray *s2, int cond);
+ void CheckAlts(Node *p);
+ void CheckLL1();
+
+ //------------- check if resolvers are legal --------------------
+
+ void ResErr(Node *p, const wchar_t* msg);
+ void CheckRes(Node *p, bool rslvAllowed);
+ void CheckResolvers();
+
+ //------------- check if every nts has a production --------------------
+
+ bool NtsComplete();
+
+ //-------------- check if every nts can be reached -----------------
+
+ void MarkReachedNts(Node *p);
+ bool AllNtReached();
+
+ //--------- check if every nts can be derived to terminals ------------
+
+ bool IsTerm(Node *p, BitArray *mark); // true if graph can be derived to terminals
+ bool AllNtToTerm();
+
+ //---------------------------------------------------------------------
+ // Cross reference list
+ //---------------------------------------------------------------------
+
+ void XRef();
+ void SetDDT(const wchar_t* s);
+ void SetOption(const wchar_t* s);
+
+};
+
+}; // namespace
+
+#endif // !defined(COCO_TAB_H__)
diff --git a/old/cococpp/Target.cpp b/old/cococpp/Target.cpp
new file mode 100644
index 0000000..dcbeefe
--- /dev/null
+++ b/old/cococpp/Target.cpp
@@ -0,0 +1,41 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include "Target.h"
+#include "State.h"
+
+namespace Coco {
+
+Target::Target(State *s) {
+ next = NULL;
+
+ state = s;
+}
+
+}; // namespace
diff --git a/old/cococpp/Target.h b/old/cococpp/Target.h
new file mode 100644
index 0000000..c54d4ca
--- /dev/null
+++ b/old/cococpp/Target.h
@@ -0,0 +1,48 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#if !defined(COCO_TARGET_H__)
+#define COCO_TARGET_H__
+
+namespace Coco {
+
+class State;
+
+class Target // set of states that are reached by an action
+{
+public:
+ Target (State *s);
+
+ State *state; // target state
+ Target *next;
+
+};
+
+}; // namespace
+
+#endif // !defined(COCO_TARGET_H__)
diff --git a/old/cococpp/build.bat b/old/cococpp/build.bat
new file mode 100644
index 0000000..8f2d0ad
--- /dev/null
+++ b/old/cococpp/build.bat
@@ -0,0 +1,3 @@
+cl *.cpp -FeCoco.exe /O2 /wd4996
+
+del *.obj
diff --git a/old/cococpp/build.sh b/old/cococpp/build.sh
new file mode 100644
index 0000000..782f79e
--- /dev/null
+++ b/old/cococpp/build.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+g++ *.cpp -o Coco -g -Wall
+
diff --git a/old/cococpp/coc.bat b/old/cococpp/coc.bat
new file mode 100644
index 0000000..3559b1e
--- /dev/null
+++ b/old/cococpp/coc.bat
@@ -0,0 +1 @@
+coco Coco.ATG -namespace Coco \ No newline at end of file
diff --git a/old/cococpp/coc.sh b/old/cococpp/coc.sh
new file mode 100644
index 0000000..3cdcf1e
--- /dev/null
+++ b/old/cococpp/coc.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+./Coco Coco.atg -namespace Coco
diff --git a/old/cococpp/cygBuild.bat b/old/cococpp/cygBuild.bat
new file mode 100644
index 0000000..7b742c6
--- /dev/null
+++ b/old/cococpp/cygBuild.bat
@@ -0,0 +1 @@
+g++ *.cpp -o Coco.exe
diff --git a/old/cococpp/mingwbuild.bat b/old/cococpp/mingwbuild.bat
new file mode 100644
index 0000000..81a2dd0
--- /dev/null
+++ b/old/cococpp/mingwbuild.bat
@@ -0,0 +1,2 @@
+C:\MinGW\bin\g++ *.cpp -o Coco.exe
+
diff --git a/old/cococpp/zipsources.bat b/old/cococpp/zipsources.bat
new file mode 100644
index 0000000..bff4e9a
--- /dev/null
+++ b/old/cococpp/zipsources.bat
@@ -0,0 +1 @@
+jar -cfM CocoSourcesCPP.zip *.atg *.frame *.bat *.h *.cpp *.sh Makefile
diff --git a/old/cocoebnf/EBNF.atg b/old/cocoebnf/EBNF.atg
new file mode 100644
index 0000000..145b975
--- /dev/null
+++ b/old/cocoebnf/EBNF.atg
@@ -0,0 +1,51 @@
+#include <iostream>
+#include <wchar.h>
+
+COMPILER EBNF
+
+CHARACTERS
+
+Letter = 'A' .. 'Z' + 'a' .. 'z' .
+Digit = '0' .. '9' .
+StringChar = ANY - "\"" .
+
+cr = '\r' .
+lf = '\n' .
+tab = '\t' .
+
+TOKENS
+
+Ident = Letter { Letter | Digit } .
+
+String = "\"" { StringChar } "\"" .
+
+IGNORE cr + lf + tab
+
+PRODUCTIONS
+
+EBNF = { Production } .
+
+Production = (. wchar_t *name; .)
+Identifier<name> (. coco_string_delete( name ); .)
+"="
+Expression
+"."
+.
+
+Expression = Term { "|" Term } .
+
+Term = Factor { Factor } .
+
+Factor = (. wchar_t *name; .)
+Identifier<name> (. std::wcout << "ident: " << name << std::endl;
+ coco_string_delete( name ); .)
+|
+String (. std::wcout << "literal: " << t->val << std::endl; .)
+|
+"(" Expression ")" | "[" Expression "]" | "{" Expression "}" .
+
+Identifier<wchar_t* &name>
+= Ident (. name = coco_string_create( t->val ); .)
+.
+
+END EBNF.
diff --git a/old/cocoebnf/Makefile b/old/cocoebnf/Makefile
new file mode 100644
index 0000000..e2caee1
--- /dev/null
+++ b/old/cocoebnf/Makefile
@@ -0,0 +1,15 @@
+all: ebnf
+
+ebnf: Scanner.o Parser.o ebnf.o
+ g++ -o ebnf Scanner.o Parser.o ebnf.o
+
+Parser.o: Parser.cpp Parser.h
+Scanner.o: Scanner.cpp Scanner.h
+ebnf.o: ebnf.cpp Parser.h Scanner.h
+
+Scanner.cpp: EBNF.atg
+ cococpp -namespace EBNF EBNF.atg
+
+clean:
+ rm -f ebnf *.old *.o Scanner.h Scanner.cpp Parser.h Parser.cpp
+
diff --git a/old/cocoebnf/Parser.frame b/old/cocoebnf/Parser.frame
new file mode 100644
index 0000000..d229053
--- /dev/null
+++ b/old/cocoebnf/Parser.frame
@@ -0,0 +1,235 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Parser.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_PARSER_H__)
+#define COCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif // !defined(COCO_PARSER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cocoebnf/Scanner.frame b/old/cocoebnf/Scanner.frame
new file mode 100644
index 0000000..71eed98
--- /dev/null
+++ b/old/cocoebnf/Scanner.frame
@@ -0,0 +1,896 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Scanner.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_SCANNER_H__)
+#define COCO_SCANNER_H__
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// io.h and fcntl are used to ensure binary read from streams on windows
+#if _MSC_VER >= 1300
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if _MSC_VER >= 1400
+#define coco_swprintf swprintf_s
+#elif _MSC_VER >= 1300
+#define coco_swprintf _snwprintf
+#elif defined __MINGW32__
+#define coco_swprintf _snwprintf
+#else
+// assume every other compiler knows swprintf
+#define coco_swprintf swprintf
+#endif
+
+#define COCO_WCHAR_MAX 65535
+#define MIN_BUFFER_LENGTH 1024
+#define MAX_BUFFER_LENGTH (64*MIN_BUFFER_LENGTH)
+#define HEAP_BLOCK_SIZE (64*1024)
+#define COCO_CPP_NAMESPACE_SEPARATOR L':'
+
+// string handling, wide character
+wchar_t* coco_string_create(const wchar_t *value);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length);
+wchar_t* coco_string_create_upper(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen);
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2);
+wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value);
+void coco_string_delete(wchar_t* &data);
+int coco_string_length(const wchar_t* data);
+bool coco_string_endswith(const wchar_t* data, const wchar_t *value);
+int coco_string_indexof(const wchar_t* data, const wchar_t value);
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value);
+void coco_string_merge(wchar_t* &data, const wchar_t* value);
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2);
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2);
+int coco_string_hash(const wchar_t* data);
+
+// string handling, ascii character
+wchar_t* coco_string_create(const char *value);
+char* coco_string_create_char(const wchar_t *value);
+void coco_string_delete(char* &data);
+
+
+-->namespace_open
+
+class Token
+{
+public:
+ int kind; // token kind
+ int pos; // token position in bytes in the source text (starting at 0)
+ int charPos; // token position in characters in the source text (starting at 0)
+ int col; // token column (starting at 1)
+ int line; // token line (starting at 1)
+ wchar_t* val; // token value
+ Token *next; // ML 2005-03-11 Peek tokens are kept in linked list
+
+ Token();
+ ~Token();
+};
+
+class Buffer {
+// This Buffer supports the following cases:
+// 1) seekable stream (file)
+// a) whole stream in buffer
+// b) part of stream in buffer
+// 2) non seekable stream (network, console)
+private:
+ unsigned char *buf; // input buffer
+ int bufCapacity; // capacity of buf
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ FILE* stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ int ReadNextStreamChunk();
+ bool CanSeek(); // true if stream can be seeked otherwise false
+
+public:
+ static const int EoF = COCO_WCHAR_MAX + 1;
+
+ Buffer(FILE* s, bool isUserStream);
+ Buffer(const unsigned char* buf, int len);
+ Buffer(Buffer *b);
+ virtual ~Buffer();
+
+ virtual void Close();
+ virtual int Read();
+ virtual int Peek();
+ virtual wchar_t* GetString(int beg, int end);
+ virtual int GetPos();
+ virtual void SetPos(int value);
+};
+
+class UTF8Buffer : public Buffer {
+public:
+ UTF8Buffer(Buffer *b) : Buffer(b) {};
+ virtual int Read();
+};
+
+//-----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+//-----------------------------------------------------------------------------------
+class StartStates {
+private:
+ class Elem {
+ public:
+ int key, val;
+ Elem *next;
+ Elem(int key, int val) { this->key = key; this->val = val; next = NULL; }
+ };
+
+ Elem **tab;
+
+public:
+ StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~StartStates() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(int key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = ((unsigned int) key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int state(int key) {
+ Elem *e = tab[((unsigned int) key) % 128];
+ while (e != NULL && e->key != key) e = e->next;
+ return e == NULL ? 0 : e->val;
+ }
+};
+
+//-------------------------------------------------------------------------------------------
+// KeywordMap -- maps strings to integers (identifiers to keyword kinds)
+//-------------------------------------------------------------------------------------------
+class KeywordMap {
+private:
+ class Elem {
+ public:
+ wchar_t *key;
+ int val;
+ Elem *next;
+ Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; }
+ virtual ~Elem() { coco_string_delete(key); }
+ };
+
+ Elem **tab;
+
+public:
+ KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~KeywordMap() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(const wchar_t *key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = coco_string_hash(key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int get(const wchar_t *key, int defaultVal) {
+ Elem *e = tab[coco_string_hash(key) % 128];
+ while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
+ return e == NULL ? defaultVal : e->val;
+ }
+};
+
+class Scanner {
+private:
+ void *firstHeap;
+ void *heap;
+ void *heapTop;
+ void **heapEnd;
+
+ unsigned char EOL;
+ int eofSym;
+ int noSym;
+ int maxT;
+ int charSetSize;
+ StartStates start;
+ KeywordMap keywords;
+
+ Token *t; // current token
+ wchar_t *tval; // text of current token
+ int tvalLength; // length of text of current token
+ int tlen; // length of current token
+
+ Token *tokens; // list of tokens already peeked (first token is a dummy)
+ Token *pt; // current peek token
+
+ int ch; // current input character
+-->casing0
+ int pos; // byte position of current character
+ int charPos; // position by unicode characters starting with 0
+ int line; // line number of current character
+ int col; // column number of current character
+ int oldEols; // EOLs that appeared in a comment;
+
+ void CreateHeapBlock();
+ Token* CreateToken();
+ void AppendVal(Token *t);
+ void SetScannerBehindT();
+
+ void Init();
+ void NextCh();
+ void AddCh();
+-->commentsheader
+ Token* NextToken();
+
+public:
+ Buffer *buffer; // scanner buffer
+
+ Scanner(const unsigned char* buf, int len);
+ Scanner(const wchar_t* fileName);
+ Scanner(FILE* s);
+ ~Scanner();
+ Token* Scan();
+ Token* Peek();
+ void ResetPeek();
+
+}; // end Scanner
+
+-->namespace_close
+
+#endif // !defined(COCO_SCANNER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Scanner.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <memory.h>
+#include <string.h>
+#include "Scanner.h"
+
+// string handling, wide character
+
+
+wchar_t* coco_string_create(const wchar_t* value) {
+ return coco_string_create(value, 0);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex) {
+ int valueLen = 0;
+ int len = 0;
+
+ if (value) {
+ valueLen = wcslen(value);
+ len = valueLen - startIndex;
+ }
+
+ return coco_string_create(value, startIndex, len);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) {
+ int len = 0;
+ wchar_t* data;
+
+ if (value) { len = length; }
+ data = new wchar_t[len + 1];
+ wcsncpy(data, &(value[startIndex]), len);
+ data[len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_upper(const wchar_t* data) {
+ if (!data) { return NULL; }
+
+ int dataLen = 0;
+ if (data) { dataLen = wcslen(data); }
+
+ wchar_t *newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ if ((L'a' <= data[i]) && (data[i] <= L'z')) {
+ newData[i] = data[i] + (L'A' - L'a');
+ }
+ else { newData[i] = data[i]; }
+ }
+
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data) {
+ if (!data) { return NULL; }
+ int dataLen = wcslen(data);
+ return coco_string_create_lower(data, 0, dataLen);
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) {
+ if (!data) { return NULL; }
+
+ wchar_t* newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ wchar_t ch = data[startIndex + i];
+ if ((L'A' <= ch) && (ch <= L'Z')) {
+ newData[i] = ch - (L'A' - L'a');
+ }
+ else { newData[i] = ch; }
+ }
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) {
+ wchar_t* data;
+ int data1Len = 0;
+ int data2Len = 0;
+
+ if (data1) { data1Len = wcslen(data1); }
+ if (data2) {data2Len = wcslen(data2); }
+
+ data = new wchar_t[data1Len + data2Len + 1];
+
+ if (data1) { wcscpy(data, data1); }
+ if (data2) { wcscpy(data + data1Len, data2); }
+
+ data[data1Len + data2Len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) {
+ int targetLen = coco_string_length(target);
+ wchar_t* data = new wchar_t[targetLen + 2];
+ wcsncpy(data, target, targetLen);
+ data[targetLen] = appendix;
+ data[targetLen + 1] = 0;
+ return data;
+}
+
+void coco_string_delete(wchar_t* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+int coco_string_length(const wchar_t* data) {
+ if (data) { return wcslen(data); }
+ return 0;
+}
+
+bool coco_string_endswith(const wchar_t* data, const wchar_t *end) {
+ int dataLen = wcslen(data);
+ int endLen = wcslen(end);
+ return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0);
+}
+
+int coco_string_indexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcschr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcsrchr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+void coco_string_merge(wchar_t* &target, const wchar_t* appendix) {
+ if (!appendix) { return; }
+ wchar_t* data = coco_string_create_append(target, appendix);
+ delete [] target;
+ target = data;
+}
+
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp( data1, data2 ) == 0;
+}
+
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp(data1, data2);
+}
+
+int coco_string_hash(const wchar_t *data) {
+ int h = 0;
+ if (!data) { return 0; }
+ while (*data != 0) {
+ h = (h * 7) ^ *data;
+ ++data;
+ }
+ if (h < 0) { h = -h; }
+ return h;
+}
+
+// string handling, ascii character
+
+wchar_t* coco_string_create(const char* value) {
+ int len = 0;
+ if (value) { len = strlen(value); }
+ wchar_t* data = new wchar_t[len + 1];
+ for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; }
+ data[len] = 0;
+ return data;
+}
+
+char* coco_string_create_char(const wchar_t *value) {
+ int len = coco_string_length(value);
+ char *res = new char[len + 1];
+ for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; }
+ res[len] = 0;
+ return res;
+}
+
+void coco_string_delete(char* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+
+-->namespace_open
+
+Token::Token() {
+ kind = 0;
+ pos = 0;
+ col = 0;
+ line = 0;
+ val = NULL;
+ next = NULL;
+}
+
+Token::~Token() {
+ coco_string_delete(val);
+}
+
+Buffer::Buffer(FILE* s, bool isUserStream) {
+// ensure binary read on windows
+#if _MSC_VER >= 1300
+ _setmode(_fileno(s), _O_BINARY);
+#endif
+ stream = s; this->isUserStream = isUserStream;
+ if (CanSeek()) {
+ fseek(s, 0, SEEK_END);
+ fileLen = ftell(s);
+ fseek(s, 0, SEEK_SET);
+ bufLen = (fileLen < MAX_BUFFER_LENGTH) ? fileLen : MAX_BUFFER_LENGTH;
+ bufStart = INT_MAX; // nothing in the buffer so far
+ } else {
+ fileLen = bufLen = bufStart = 0;
+ }
+ bufCapacity = (bufLen>0) ? bufLen : MIN_BUFFER_LENGTH;
+ buf = new unsigned char[bufCapacity];
+ if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && CanSeek()) Close();
+}
+
+Buffer::Buffer(Buffer *b) {
+ buf = b->buf;
+ bufCapacity = b->bufCapacity;
+ b->buf = NULL;
+ bufStart = b->bufStart;
+ bufLen = b->bufLen;
+ fileLen = b->fileLen;
+ bufPos = b->bufPos;
+ stream = b->stream;
+ b->stream = NULL;
+ isUserStream = b->isUserStream;
+}
+
+Buffer::Buffer(const unsigned char* buf, int len) {
+ this->buf = new unsigned char[len];
+ memcpy(this->buf, buf, len*sizeof(unsigned char));
+ bufStart = 0;
+ bufCapacity = bufLen = len;
+ fileLen = len;
+ bufPos = 0;
+ stream = NULL;
+}
+
+Buffer::~Buffer() {
+ Close();
+ if (buf != NULL) {
+ delete [] buf;
+ buf = NULL;
+ }
+}
+
+void Buffer::Close() {
+ if (!isUserStream && stream != NULL) {
+ fclose(stream);
+ stream = NULL;
+ }
+}
+
+int Buffer::Read() {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (GetPos() < fileLen) {
+ SetPos(GetPos()); // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
+ return buf[bufPos++];
+ } else {
+ return EoF;
+ }
+}
+
+int Buffer::Peek() {
+ int curPos = GetPos();
+ int ch = Read();
+ SetPos(curPos);
+ return ch;
+}
+
+// beg .. begin, zero-based, inclusive, in byte
+// end .. end, zero-based, exclusive, in byte
+wchar_t* Buffer::GetString(int beg, int end) {
+ int len = 0;
+ wchar_t *buf = new wchar_t[end - beg];
+ int oldPos = GetPos();
+ SetPos(beg);
+ while (GetPos() < end) buf[len++] = (wchar_t) Read();
+ SetPos(oldPos);
+ wchar_t *res = coco_string_create(buf, 0, len);
+ coco_string_delete(buf);
+ return res;
+}
+
+int Buffer::GetPos() {
+ return bufPos + bufStart;
+}
+
+void Buffer::SetPos(int value) {
+ if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while ((value >= fileLen) && (ReadNextStreamChunk() > 0));
+ }
+
+ if ((value < 0) || (value > fileLen)) {
+ wprintf(L"--- buffer out of bounds access, position: %d\n", value);
+ exit(1);
+ }
+
+ if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != NULL) { // must be swapped in
+ fseek(stream, value, SEEK_SET);
+ bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
+ bufStart = value; bufPos = 0;
+ } else {
+ bufPos = fileLen - bufStart; // make Pos return fileLen
+ }
+}
+
+// Read the next chunk of bytes from the stream, increases the buffer
+// if needed and updates the fields fileLen and bufLen.
+// Returns the number of bytes read.
+int Buffer::ReadNextStreamChunk() {
+ int free = bufCapacity - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ bufCapacity = bufLen * 2;
+ unsigned char *newBuf = new unsigned char[bufCapacity];
+ memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
+ delete [] buf;
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = fread(buf + bufLen, sizeof(unsigned char), free, stream);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+}
+
+bool Buffer::CanSeek() {
+ return (stream != NULL) && (ftell(stream) != -1);
+}
+
+int UTF8Buffer::Read() {
+ int ch;
+ do {
+ ch = Buffer::Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
+ if (ch < 128 || ch == EoF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F; ch = Buffer::Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = Buffer::Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+}
+
+Scanner::Scanner(const unsigned char* buf, int len) {
+ buffer = new Buffer(buf, len);
+ Init();
+}
+
+Scanner::Scanner(const wchar_t* fileName) {
+ FILE* stream;
+ char *chFileName = coco_string_create_char(fileName);
+ if ((stream = fopen(chFileName, "rb")) == NULL) {
+ wprintf(L"--- Cannot open file %ls\n", fileName);
+ exit(1);
+ }
+ coco_string_delete(chFileName);
+ buffer = new Buffer(stream, false);
+ Init();
+}
+
+Scanner::Scanner(FILE* s) {
+ buffer = new Buffer(s, true);
+ Init();
+}
+
+Scanner::~Scanner() {
+ char* cur = (char*) firstHeap;
+
+ while(cur != NULL) {
+ cur = *(char**) (cur + HEAP_BLOCK_SIZE);
+ free(firstHeap);
+ firstHeap = cur;
+ }
+ delete [] tval;
+ delete buffer;
+}
+
+void Scanner::Init() {
+ EOL = '\n';
+ eofSym = 0;
+-->declarations
+
+ tvalLength = 128;
+ tval = new wchar_t[tvalLength]; // text of current token
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ firstHeap = heap;
+ heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heapTop = heap;
+ if (sizeof(Token) > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too small HEAP_BLOCK_SIZE\n");
+ exit(1);
+ }
+
+ pos = -1; line = 1; col = 0; charPos = -1;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ wprintf(L"Illegal byte order mark at start of file");
+ exit(1);
+ }
+ Buffer *oldBuf = buffer;
+ buffer = new UTF8Buffer(buffer); col = 0; charPos = -1;
+ delete oldBuf; oldBuf = NULL;
+ NextCh();
+ }
+
+-->initialization
+ pt = tokens = CreateToken(); // first token is a dummy
+}
+
+void Scanner::NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+ pos = buffer->GetPos();
+ // buffer reads unicode chars, if UTF8 has been detected
+ ch = buffer->Read(); col++; charPos++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
+ if (ch == EOL) { line++; col = 0; }
+ }
+-->casing1
+}
+
+void Scanner::AddCh() {
+ if (tlen >= tvalLength) {
+ tvalLength *= 2;
+ wchar_t *newBuf = new wchar_t[tvalLength];
+ memcpy(newBuf, tval, tlen*sizeof(wchar_t));
+ delete [] tval;
+ tval = newBuf;
+ }
+ if (ch != Buffer::EoF) {
+-->casing2
+ NextCh();
+ }
+}
+
+-->comments
+
+void Scanner::CreateHeapBlock() {
+ void* newHeap;
+ char* cur = (char*) firstHeap;
+
+ while(((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) {
+ cur = *((char**) (cur + HEAP_BLOCK_SIZE));
+ free(firstHeap);
+ firstHeap = cur;
+ }
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ *heapEnd = newHeap;
+ heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heap = newHeap;
+ heapTop = heap;
+}
+
+Token* Scanner::CreateToken() {
+ Token *t;
+ if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
+ CreateHeapBlock();
+ }
+ t = (Token*) heapTop;
+ heapTop = (void*) ((char*) heapTop + sizeof(Token));
+ t->val = NULL;
+ t->next = NULL;
+ return t;
+}
+
+void Scanner::AppendVal(Token *t) {
+ int reqMem = (tlen + 1) * sizeof(wchar_t);
+ if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
+ if (reqMem > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too long token value\n");
+ exit(1);
+ }
+ CreateHeapBlock();
+ }
+ t->val = (wchar_t*) heapTop;
+ heapTop = (void*) ((char*) heapTop + reqMem);
+
+ wcsncpy(t->val, tval, tlen);
+ t->val[tlen] = L'\0';
+}
+
+Token* Scanner::NextToken() {
+ while (ch == ' ' ||
+-->scan1
+ ) NextCh();
+-->scan2
+ int recKind = noSym;
+ int recEnd = pos;
+ t = CreateToken();
+ t->pos = pos; t->col = col; t->line = line; t->charPos = charPos;
+ int state = start.state(ch);
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t->kind = eofSym; break; } // NextCh already done
+ case 0: {
+ case_0:
+ if (recKind != noSym) {
+ tlen = recEnd - t->pos;
+ SetScannerBehindT();
+ }
+ t->kind = recKind; break;
+ } // NextCh already done
+-->scan3
+ }
+ AppendVal(t);
+ return t;
+}
+
+void Scanner::SetScannerBehindT() {
+ buffer->SetPos(t->pos);
+ NextCh();
+ line = t->line; col = t->col; charPos = t->charPos;
+ for (int i = 0; i < tlen; i++) NextCh();
+}
+
+// get the next token (possibly a token already seen during peeking)
+Token* Scanner::Scan() {
+ if (tokens->next == NULL) {
+ return pt = tokens = NextToken();
+ } else {
+ pt = tokens = tokens->next;
+ return tokens;
+ }
+}
+
+// peek for the next token, ignore pragmas
+Token* Scanner::Peek() {
+ do {
+ if (pt->next == NULL) {
+ pt->next = NextToken();
+ }
+ pt = pt->next;
+ } while (pt->kind > maxT); // skip pragmas
+
+ return pt;
+}
+
+// make sure that peeking starts at the current scan position
+void Scanner::ResetPeek() {
+ pt = tokens;
+}
+
+-->namespace_close
diff --git a/old/cocoebnf/ebnf.cpp b/old/cocoebnf/ebnf.cpp
new file mode 100644
index 0000000..61758ec
--- /dev/null
+++ b/old/cocoebnf/ebnf.cpp
@@ -0,0 +1,24 @@
+#include "Parser.h"
+#include "Scanner.h"
+
+#include <iostream>
+#include <wchar.h>
+
+int main( int argc, char *argv[] )
+{
+ if( argc != 2 ) {
+ std::cerr << "usage: EBNF <filename>" << std::endl;
+ return 1;
+ }
+
+ wchar_t *filename = coco_string_create( argv[1] );
+ EBNF::Scanner *scanner = new EBNF::Scanner( filename );
+ EBNF::Parser *parser = new EBNF::Parser( scanner );
+ parser->Parse( );
+
+ delete parser;
+ delete scanner;
+ coco_string_delete( filename );
+
+ return 0;
+}
diff --git a/old/cocoo0c/Makefile b/old/cocoo0c/Makefile
new file mode 100644
index 0000000..4f9c83f
--- /dev/null
+++ b/old/cocoo0c/Makefile
@@ -0,0 +1,23 @@
+all: o0c
+
+o0c: Scanner.o Parser.o o0c.o
+ g++ -o o0c Scanner.o Parser.o o0c.o
+
+Parser.o: Parser.cpp Parser.h
+Scanner.o: Scanner.cpp Scanner.h
+o0c.o: o0c.cpp Parser.h Scanner.h
+
+Scanner.cpp: Oberon0.atg
+ cococpp -namespace Oberon0 Oberon0.atg
+
+test: o0c
+ @echo "** TEST 0"
+ @./o0c test0.o0
+ @echo "** TEST 1"
+ @./o0c test1.o0
+ @echo "** TEST 2"
+ @./o0c test2.o0
+
+clean:
+ rm -f o0c *.old *.o Scanner.h Scanner.cpp Parser.h Parser.cpp
+
diff --git a/old/cocoo0c/Oberon0.atg b/old/cocoo0c/Oberon0.atg
new file mode 100644
index 0000000..f65bb15
--- /dev/null
+++ b/old/cocoo0c/Oberon0.atg
@@ -0,0 +1,45 @@
+#include <iostream>
+#include <wchar.h>
+
+COMPILER Oberon0
+
+CHARACTERS
+
+ letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
+ digit = "0123456789".
+ hexDigit = "0123456789ABCDEF".
+ cr = '\r'.
+ lf = '\n'.
+ tab = '\t'.
+ stringCh = ANY - "'" - '"' - cr - lf.
+
+TOKENS
+
+ ident = letter { letter | digit }.
+ integer = digit { digit }.
+ string = "'" { stringCh | "'" } '"' | "'" { stringCh | '"' } "'".
+
+ dot = ".".
+
+COMMENTS FROM "(*" TO "*)" NESTED
+
+IGNORE cr + lf + tab
+
+PRODUCTIONS
+
+Oberon0 = (. wchar_t *modname, *modname2; .)
+ "MODULE" Ident<modname> ";"
+ "BEGIN"
+ "END" Ident<modname2> (.
+ if( coco_string_compareto( modname, modname2 ) != 0 ) {
+ SemErr( L"Module name mismatch" );
+ }
+ .)
+ "."
+ EOF.
+
+Ident<wchar_t *&modname>
+= ident (. modname = coco_string_create( t->val ); .)
+.
+
+END Oberon0.
diff --git a/old/cocoo0c/Oberon2.atg b/old/cocoo0c/Oberon2.atg
new file mode 100644
index 0000000..a8097ac
--- /dev/null
+++ b/old/cocoo0c/Oberon2.atg
@@ -0,0 +1,229 @@
+import java.util.HashSet;
+
+COMPILER Oberon2
+
+/*
+Source: http://www.zel.org/aos/o2report.htm
+
+The Programming Language Oberon-2
+
+H. Mössenböck, N. Wirth, Institut für Computersysteme, ETH Zürich, 1992-1996
+
+Changes:
+ - Enclosed all keywords with double quotes
+ - Renamed start symbol "Module" to Oberon2
+ - Added production ImportListMember
+ Please note that the optional part of the production is different from
+ the original. This solves a LL(1) conflict, but introduces a slightly
+ different meaning: in the original grammar, the emphasis is on the
+ imported module name, which might be referenced via an alias name.
+ This definition emphasis the alias name, which now may be backed up
+ by a module with a different name....
+ - Moved the token "PROCEDURE" out of the ProcDecl and ForwardDecl
+ productions into the DeclSeq production to solve a LL(1) conflict.
+ - Added a new production for non terminal number
+ - Added two conflict resolvers
+*/
+
+public static void main(String[] args) {
+ Scanner scanner = new Scanner(args[0]);
+ Parser parser = new Parser(scanner);
+ parser.Parse();
+ System.out.println("Done.");
+}
+
+private HashSet<String> modules = new HashSet<String>();
+
+/* Returns true if the next ident is a module name */
+private boolean isModule() {
+ if (la.kind == _ident) {
+ return modules.contains(la.val);
+ }
+ return false;
+}
+
+/* Returns true if the current look ahead symbol is
+ part of the current scanned designator. */
+private boolean isDesignatorPart() {
+ switch (la.kind) {
+ case _dot:
+ case _lbrack:
+ case _arrow:
+ return true;
+ case _lpar:
+ /* Semantic analysis is missing! */
+ /* Assumes for now a procedure invocation. */
+ return false;
+ default:
+ return false;
+ }
+}
+
+CHARACTERS
+ letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
+ digit = "0123456789".
+ hexDigit = "0123456789ABCDEF".
+ cr = '\r'.
+ lf = '\n'.
+ tab = '\t'.
+ stringCh = ANY - "'" - '"' - cr - lf.
+
+TOKENS
+ ident = letter { letter | digit }.
+ integer = digit { digit }
+ | digit { digit } CONTEXT ("..")
+ | digit { hexDigit } "H".
+ real = digit { digit } "." { digit } [("E" | "D") ["+" | "-"] digit {digit}].
+ string = '"' { stringCh | "'" } '"' | "'" { stringCh | '"' } "'".
+ character = digit { hexDigit } "X".
+
+ dot = ".".
+ lbrack = "[".
+ arrow = "^".
+ lpar = "(".
+
+COMMENTS FROM "(*" TO "*)" NESTED
+
+IGNORE cr + lf + tab
+
+PRODUCTIONS
+
+Oberon2
+ = "MODULE" ident ";" [ImportList] DeclSeq ["BEGIN" StatementSeq] "END" ident ".".
+
+ImportList
+ = "IMPORT" ImportListMember {"," ImportListMember } ";".
+
+ImportListMember
+ = ident (. modules.add(t.val); .) [":=" ident ].
+
+DeclSeq
+ = { "CONST" {ConstDecl ";" } | "TYPE" {TypeDecl ";"} | "VAR" {VarDecl ";"}}
+ { "PROCEDURE" (ProcDecl | ForwardDecl) ";"}.
+
+ConstDecl
+ = IdentDef "=" ConstExpr.
+
+TypeDecl
+ = IdentDef "=" Type.
+
+VarDecl
+ = IdentList ":" Type.
+
+ProcDecl
+ = [Receiver] IdentDef [FormalPars] ";" DeclSeq ["BEGIN" StatementSeq] "END" ident.
+
+ForwardDecl
+ = "^" [Receiver] IdentDef [FormalPars].
+
+FormalPars
+ = "(" [FPSection {";" FPSection}] ")" [":" Qualident].
+
+FPSection
+ = ["VAR"] ident {"," ident} ":" Type.
+
+Receiver
+ = "(" ["VAR"] ident ":" ident ")".
+
+Type
+ = Qualident
+ | "ARRAY" [ConstExpr {"," ConstExpr}] "OF" Type
+ | "RECORD" ["("Qualident")"] FieldList {";" FieldList} "END"
+ | "POINTER" "TO" Type
+ | "PROCEDURE" [FormalPars]
+ .
+
+FieldList
+ = [IdentList ":" Type].
+
+StatementSeq
+ = Statement {";" Statement}.
+
+Statement
+ = [ Designator (":=" Expr | ["(" [ExprList] ")"])
+ | "IF" Expr "THEN" StatementSeq
+ {"ELSIF" Expr "THEN" StatementSeq}
+ ["ELSE" StatementSeq]
+ "END"
+ | "CASE" Expr "OF" Case
+ {"|" Case}
+ ["ELSE" StatementSeq]
+ "END"
+ | "WHILE" Expr "DO" StatementSeq "END"
+ | "REPEAT" StatementSeq "UNTIL" Expr
+ | "FOR" ident ":=" Expr "TO" Expr ["BY" ConstExpr] "DO" StatementSeq "END"
+ | "LOOP" StatementSeq "END"
+ | "WITH" Guard "DO" StatementSeq
+ {"|" Guard "DO" StatementSeq}
+ ["ELSE" StatementSeq]
+ "END"
+ | "EXIT"
+ | "RETURN" [Expr]
+ ]
+ .
+
+Case
+ = [CaseLabels {"," CaseLabels} ":" StatementSeq].
+
+CaseLabels
+ = ConstExpr [".." ConstExpr].
+
+Guard
+ = Qualident ":" Qualident.
+
+ConstExpr
+ = Expr.
+
+Expr
+ = SimpleExpr [Relation SimpleExpr].
+
+SimpleExpr
+ = ["+" | "-"] Term {AddOp Term}.
+
+Term
+ = Factor {MulOp Factor}.
+Factor
+ = Designator ["(" [ExprList] ")"]
+ | number
+ | character
+ | string
+ | "NIL"
+ | Set
+ | "(" Expr ")"
+ | "~" Factor
+ .
+
+Set
+ = "{" [Element {"," Element}] "}".
+
+Element
+ = Expr [".." Expr].
+
+Relation
+ = "=" | "#" | "<" | "<=" | ">" | ">=" | "IN" | "IS".
+
+AddOp
+ = "+" | "-" | "OR".
+
+MulOp
+ = "*" | "/" | "DIV" | "MOD" | "&".
+
+Designator
+ = Qualident { IF(isDesignatorPart()) ("." ident | "[" ExprList "]" | "^" | "(" Qualident ")") }.
+
+ExprList
+ = Expr {"," Expr}.
+
+IdentList
+ = IdentDef {"," IdentDef}.
+
+Qualident
+ = [IF(isModule()) ident "."] ident.
+
+IdentDef
+ = ident ["*" | "-"].
+
+number
+ = integer | real.
+
+END Oberon2. \ No newline at end of file
diff --git a/old/cocoo0c/Parser.frame b/old/cocoo0c/Parser.frame
new file mode 100644
index 0000000..d229053
--- /dev/null
+++ b/old/cocoo0c/Parser.frame
@@ -0,0 +1,235 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Parser.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_PARSER_H__)
+#define COCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif // !defined(COCO_PARSER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cocoo0c/Parser.h b/old/cocoo0c/Parser.h
new file mode 100644
index 0000000..59b8b1e
--- /dev/null
+++ b/old/cocoo0c/Parser.h
@@ -0,0 +1,203 @@
+
+
+#if !defined(COCO_PARSER_H__)
+#define COCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif // !defined(COCO_PARSER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cocoo0c/Scanner.frame b/old/cocoo0c/Scanner.frame
new file mode 100644
index 0000000..71eed98
--- /dev/null
+++ b/old/cocoo0c/Scanner.frame
@@ -0,0 +1,896 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Scanner.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_SCANNER_H__)
+#define COCO_SCANNER_H__
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// io.h and fcntl are used to ensure binary read from streams on windows
+#if _MSC_VER >= 1300
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if _MSC_VER >= 1400
+#define coco_swprintf swprintf_s
+#elif _MSC_VER >= 1300
+#define coco_swprintf _snwprintf
+#elif defined __MINGW32__
+#define coco_swprintf _snwprintf
+#else
+// assume every other compiler knows swprintf
+#define coco_swprintf swprintf
+#endif
+
+#define COCO_WCHAR_MAX 65535
+#define MIN_BUFFER_LENGTH 1024
+#define MAX_BUFFER_LENGTH (64*MIN_BUFFER_LENGTH)
+#define HEAP_BLOCK_SIZE (64*1024)
+#define COCO_CPP_NAMESPACE_SEPARATOR L':'
+
+// string handling, wide character
+wchar_t* coco_string_create(const wchar_t *value);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length);
+wchar_t* coco_string_create_upper(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen);
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2);
+wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value);
+void coco_string_delete(wchar_t* &data);
+int coco_string_length(const wchar_t* data);
+bool coco_string_endswith(const wchar_t* data, const wchar_t *value);
+int coco_string_indexof(const wchar_t* data, const wchar_t value);
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value);
+void coco_string_merge(wchar_t* &data, const wchar_t* value);
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2);
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2);
+int coco_string_hash(const wchar_t* data);
+
+// string handling, ascii character
+wchar_t* coco_string_create(const char *value);
+char* coco_string_create_char(const wchar_t *value);
+void coco_string_delete(char* &data);
+
+
+-->namespace_open
+
+class Token
+{
+public:
+ int kind; // token kind
+ int pos; // token position in bytes in the source text (starting at 0)
+ int charPos; // token position in characters in the source text (starting at 0)
+ int col; // token column (starting at 1)
+ int line; // token line (starting at 1)
+ wchar_t* val; // token value
+ Token *next; // ML 2005-03-11 Peek tokens are kept in linked list
+
+ Token();
+ ~Token();
+};
+
+class Buffer {
+// This Buffer supports the following cases:
+// 1) seekable stream (file)
+// a) whole stream in buffer
+// b) part of stream in buffer
+// 2) non seekable stream (network, console)
+private:
+ unsigned char *buf; // input buffer
+ int bufCapacity; // capacity of buf
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ FILE* stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ int ReadNextStreamChunk();
+ bool CanSeek(); // true if stream can be seeked otherwise false
+
+public:
+ static const int EoF = COCO_WCHAR_MAX + 1;
+
+ Buffer(FILE* s, bool isUserStream);
+ Buffer(const unsigned char* buf, int len);
+ Buffer(Buffer *b);
+ virtual ~Buffer();
+
+ virtual void Close();
+ virtual int Read();
+ virtual int Peek();
+ virtual wchar_t* GetString(int beg, int end);
+ virtual int GetPos();
+ virtual void SetPos(int value);
+};
+
+class UTF8Buffer : public Buffer {
+public:
+ UTF8Buffer(Buffer *b) : Buffer(b) {};
+ virtual int Read();
+};
+
+//-----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+//-----------------------------------------------------------------------------------
+class StartStates {
+private:
+ class Elem {
+ public:
+ int key, val;
+ Elem *next;
+ Elem(int key, int val) { this->key = key; this->val = val; next = NULL; }
+ };
+
+ Elem **tab;
+
+public:
+ StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~StartStates() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(int key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = ((unsigned int) key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int state(int key) {
+ Elem *e = tab[((unsigned int) key) % 128];
+ while (e != NULL && e->key != key) e = e->next;
+ return e == NULL ? 0 : e->val;
+ }
+};
+
+//-------------------------------------------------------------------------------------------
+// KeywordMap -- maps strings to integers (identifiers to keyword kinds)
+//-------------------------------------------------------------------------------------------
+class KeywordMap {
+private:
+ class Elem {
+ public:
+ wchar_t *key;
+ int val;
+ Elem *next;
+ Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; }
+ virtual ~Elem() { coco_string_delete(key); }
+ };
+
+ Elem **tab;
+
+public:
+ KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~KeywordMap() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(const wchar_t *key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = coco_string_hash(key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int get(const wchar_t *key, int defaultVal) {
+ Elem *e = tab[coco_string_hash(key) % 128];
+ while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
+ return e == NULL ? defaultVal : e->val;
+ }
+};
+
+class Scanner {
+private:
+ void *firstHeap;
+ void *heap;
+ void *heapTop;
+ void **heapEnd;
+
+ unsigned char EOL;
+ int eofSym;
+ int noSym;
+ int maxT;
+ int charSetSize;
+ StartStates start;
+ KeywordMap keywords;
+
+ Token *t; // current token
+ wchar_t *tval; // text of current token
+ int tvalLength; // length of text of current token
+ int tlen; // length of current token
+
+ Token *tokens; // list of tokens already peeked (first token is a dummy)
+ Token *pt; // current peek token
+
+ int ch; // current input character
+-->casing0
+ int pos; // byte position of current character
+ int charPos; // position by unicode characters starting with 0
+ int line; // line number of current character
+ int col; // column number of current character
+ int oldEols; // EOLs that appeared in a comment;
+
+ void CreateHeapBlock();
+ Token* CreateToken();
+ void AppendVal(Token *t);
+ void SetScannerBehindT();
+
+ void Init();
+ void NextCh();
+ void AddCh();
+-->commentsheader
+ Token* NextToken();
+
+public:
+ Buffer *buffer; // scanner buffer
+
+ Scanner(const unsigned char* buf, int len);
+ Scanner(const wchar_t* fileName);
+ Scanner(FILE* s);
+ ~Scanner();
+ Token* Scan();
+ Token* Peek();
+ void ResetPeek();
+
+}; // end Scanner
+
+-->namespace_close
+
+#endif // !defined(COCO_SCANNER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Scanner.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <memory.h>
+#include <string.h>
+#include "Scanner.h"
+
+// string handling, wide character
+
+
+wchar_t* coco_string_create(const wchar_t* value) {
+ return coco_string_create(value, 0);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex) {
+ int valueLen = 0;
+ int len = 0;
+
+ if (value) {
+ valueLen = wcslen(value);
+ len = valueLen - startIndex;
+ }
+
+ return coco_string_create(value, startIndex, len);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) {
+ int len = 0;
+ wchar_t* data;
+
+ if (value) { len = length; }
+ data = new wchar_t[len + 1];
+ wcsncpy(data, &(value[startIndex]), len);
+ data[len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_upper(const wchar_t* data) {
+ if (!data) { return NULL; }
+
+ int dataLen = 0;
+ if (data) { dataLen = wcslen(data); }
+
+ wchar_t *newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ if ((L'a' <= data[i]) && (data[i] <= L'z')) {
+ newData[i] = data[i] + (L'A' - L'a');
+ }
+ else { newData[i] = data[i]; }
+ }
+
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data) {
+ if (!data) { return NULL; }
+ int dataLen = wcslen(data);
+ return coco_string_create_lower(data, 0, dataLen);
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) {
+ if (!data) { return NULL; }
+
+ wchar_t* newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ wchar_t ch = data[startIndex + i];
+ if ((L'A' <= ch) && (ch <= L'Z')) {
+ newData[i] = ch - (L'A' - L'a');
+ }
+ else { newData[i] = ch; }
+ }
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) {
+ wchar_t* data;
+ int data1Len = 0;
+ int data2Len = 0;
+
+ if (data1) { data1Len = wcslen(data1); }
+ if (data2) {data2Len = wcslen(data2); }
+
+ data = new wchar_t[data1Len + data2Len + 1];
+
+ if (data1) { wcscpy(data, data1); }
+ if (data2) { wcscpy(data + data1Len, data2); }
+
+ data[data1Len + data2Len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) {
+ int targetLen = coco_string_length(target);
+ wchar_t* data = new wchar_t[targetLen + 2];
+ wcsncpy(data, target, targetLen);
+ data[targetLen] = appendix;
+ data[targetLen + 1] = 0;
+ return data;
+}
+
+void coco_string_delete(wchar_t* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+int coco_string_length(const wchar_t* data) {
+ if (data) { return wcslen(data); }
+ return 0;
+}
+
+bool coco_string_endswith(const wchar_t* data, const wchar_t *end) {
+ int dataLen = wcslen(data);
+ int endLen = wcslen(end);
+ return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0);
+}
+
+int coco_string_indexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcschr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcsrchr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+void coco_string_merge(wchar_t* &target, const wchar_t* appendix) {
+ if (!appendix) { return; }
+ wchar_t* data = coco_string_create_append(target, appendix);
+ delete [] target;
+ target = data;
+}
+
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp( data1, data2 ) == 0;
+}
+
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp(data1, data2);
+}
+
+int coco_string_hash(const wchar_t *data) {
+ int h = 0;
+ if (!data) { return 0; }
+ while (*data != 0) {
+ h = (h * 7) ^ *data;
+ ++data;
+ }
+ if (h < 0) { h = -h; }
+ return h;
+}
+
+// string handling, ascii character
+
+wchar_t* coco_string_create(const char* value) {
+ int len = 0;
+ if (value) { len = strlen(value); }
+ wchar_t* data = new wchar_t[len + 1];
+ for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; }
+ data[len] = 0;
+ return data;
+}
+
+char* coco_string_create_char(const wchar_t *value) {
+ int len = coco_string_length(value);
+ char *res = new char[len + 1];
+ for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; }
+ res[len] = 0;
+ return res;
+}
+
+void coco_string_delete(char* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+
+-->namespace_open
+
+Token::Token() {
+ kind = 0;
+ pos = 0;
+ col = 0;
+ line = 0;
+ val = NULL;
+ next = NULL;
+}
+
+Token::~Token() {
+ coco_string_delete(val);
+}
+
+Buffer::Buffer(FILE* s, bool isUserStream) {
+// ensure binary read on windows
+#if _MSC_VER >= 1300
+ _setmode(_fileno(s), _O_BINARY);
+#endif
+ stream = s; this->isUserStream = isUserStream;
+ if (CanSeek()) {
+ fseek(s, 0, SEEK_END);
+ fileLen = ftell(s);
+ fseek(s, 0, SEEK_SET);
+ bufLen = (fileLen < MAX_BUFFER_LENGTH) ? fileLen : MAX_BUFFER_LENGTH;
+ bufStart = INT_MAX; // nothing in the buffer so far
+ } else {
+ fileLen = bufLen = bufStart = 0;
+ }
+ bufCapacity = (bufLen>0) ? bufLen : MIN_BUFFER_LENGTH;
+ buf = new unsigned char[bufCapacity];
+ if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && CanSeek()) Close();
+}
+
+Buffer::Buffer(Buffer *b) {
+ buf = b->buf;
+ bufCapacity = b->bufCapacity;
+ b->buf = NULL;
+ bufStart = b->bufStart;
+ bufLen = b->bufLen;
+ fileLen = b->fileLen;
+ bufPos = b->bufPos;
+ stream = b->stream;
+ b->stream = NULL;
+ isUserStream = b->isUserStream;
+}
+
+Buffer::Buffer(const unsigned char* buf, int len) {
+ this->buf = new unsigned char[len];
+ memcpy(this->buf, buf, len*sizeof(unsigned char));
+ bufStart = 0;
+ bufCapacity = bufLen = len;
+ fileLen = len;
+ bufPos = 0;
+ stream = NULL;
+}
+
+Buffer::~Buffer() {
+ Close();
+ if (buf != NULL) {
+ delete [] buf;
+ buf = NULL;
+ }
+}
+
+void Buffer::Close() {
+ if (!isUserStream && stream != NULL) {
+ fclose(stream);
+ stream = NULL;
+ }
+}
+
+int Buffer::Read() {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (GetPos() < fileLen) {
+ SetPos(GetPos()); // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
+ return buf[bufPos++];
+ } else {
+ return EoF;
+ }
+}
+
+int Buffer::Peek() {
+ int curPos = GetPos();
+ int ch = Read();
+ SetPos(curPos);
+ return ch;
+}
+
+// beg .. begin, zero-based, inclusive, in byte
+// end .. end, zero-based, exclusive, in byte
+wchar_t* Buffer::GetString(int beg, int end) {
+ int len = 0;
+ wchar_t *buf = new wchar_t[end - beg];
+ int oldPos = GetPos();
+ SetPos(beg);
+ while (GetPos() < end) buf[len++] = (wchar_t) Read();
+ SetPos(oldPos);
+ wchar_t *res = coco_string_create(buf, 0, len);
+ coco_string_delete(buf);
+ return res;
+}
+
+int Buffer::GetPos() {
+ return bufPos + bufStart;
+}
+
+void Buffer::SetPos(int value) {
+ if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while ((value >= fileLen) && (ReadNextStreamChunk() > 0));
+ }
+
+ if ((value < 0) || (value > fileLen)) {
+ wprintf(L"--- buffer out of bounds access, position: %d\n", value);
+ exit(1);
+ }
+
+ if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != NULL) { // must be swapped in
+ fseek(stream, value, SEEK_SET);
+ bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
+ bufStart = value; bufPos = 0;
+ } else {
+ bufPos = fileLen - bufStart; // make Pos return fileLen
+ }
+}
+
+// Read the next chunk of bytes from the stream, increases the buffer
+// if needed and updates the fields fileLen and bufLen.
+// Returns the number of bytes read.
+int Buffer::ReadNextStreamChunk() {
+ int free = bufCapacity - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ bufCapacity = bufLen * 2;
+ unsigned char *newBuf = new unsigned char[bufCapacity];
+ memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
+ delete [] buf;
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = fread(buf + bufLen, sizeof(unsigned char), free, stream);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+}
+
+bool Buffer::CanSeek() {
+ return (stream != NULL) && (ftell(stream) != -1);
+}
+
+int UTF8Buffer::Read() {
+ int ch;
+ do {
+ ch = Buffer::Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
+ if (ch < 128 || ch == EoF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F; ch = Buffer::Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = Buffer::Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+}
+
+Scanner::Scanner(const unsigned char* buf, int len) {
+ buffer = new Buffer(buf, len);
+ Init();
+}
+
+Scanner::Scanner(const wchar_t* fileName) {
+ FILE* stream;
+ char *chFileName = coco_string_create_char(fileName);
+ if ((stream = fopen(chFileName, "rb")) == NULL) {
+ wprintf(L"--- Cannot open file %ls\n", fileName);
+ exit(1);
+ }
+ coco_string_delete(chFileName);
+ buffer = new Buffer(stream, false);
+ Init();
+}
+
+Scanner::Scanner(FILE* s) {
+ buffer = new Buffer(s, true);
+ Init();
+}
+
+Scanner::~Scanner() {
+ char* cur = (char*) firstHeap;
+
+ while(cur != NULL) {
+ cur = *(char**) (cur + HEAP_BLOCK_SIZE);
+ free(firstHeap);
+ firstHeap = cur;
+ }
+ delete [] tval;
+ delete buffer;
+}
+
+void Scanner::Init() {
+ EOL = '\n';
+ eofSym = 0;
+-->declarations
+
+ tvalLength = 128;
+ tval = new wchar_t[tvalLength]; // text of current token
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ firstHeap = heap;
+ heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heapTop = heap;
+ if (sizeof(Token) > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too small HEAP_BLOCK_SIZE\n");
+ exit(1);
+ }
+
+ pos = -1; line = 1; col = 0; charPos = -1;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ wprintf(L"Illegal byte order mark at start of file");
+ exit(1);
+ }
+ Buffer *oldBuf = buffer;
+ buffer = new UTF8Buffer(buffer); col = 0; charPos = -1;
+ delete oldBuf; oldBuf = NULL;
+ NextCh();
+ }
+
+-->initialization
+ pt = tokens = CreateToken(); // first token is a dummy
+}
+
+void Scanner::NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+ pos = buffer->GetPos();
+ // buffer reads unicode chars, if UTF8 has been detected
+ ch = buffer->Read(); col++; charPos++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
+ if (ch == EOL) { line++; col = 0; }
+ }
+-->casing1
+}
+
+void Scanner::AddCh() {
+ if (tlen >= tvalLength) {
+ tvalLength *= 2;
+ wchar_t *newBuf = new wchar_t[tvalLength];
+ memcpy(newBuf, tval, tlen*sizeof(wchar_t));
+ delete [] tval;
+ tval = newBuf;
+ }
+ if (ch != Buffer::EoF) {
+-->casing2
+ NextCh();
+ }
+}
+
+-->comments
+
+void Scanner::CreateHeapBlock() {
+ void* newHeap;
+ char* cur = (char*) firstHeap;
+
+ while(((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) {
+ cur = *((char**) (cur + HEAP_BLOCK_SIZE));
+ free(firstHeap);
+ firstHeap = cur;
+ }
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ *heapEnd = newHeap;
+ heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heap = newHeap;
+ heapTop = heap;
+}
+
+Token* Scanner::CreateToken() {
+ Token *t;
+ if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
+ CreateHeapBlock();
+ }
+ t = (Token*) heapTop;
+ heapTop = (void*) ((char*) heapTop + sizeof(Token));
+ t->val = NULL;
+ t->next = NULL;
+ return t;
+}
+
+void Scanner::AppendVal(Token *t) {
+ int reqMem = (tlen + 1) * sizeof(wchar_t);
+ if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
+ if (reqMem > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too long token value\n");
+ exit(1);
+ }
+ CreateHeapBlock();
+ }
+ t->val = (wchar_t*) heapTop;
+ heapTop = (void*) ((char*) heapTop + reqMem);
+
+ wcsncpy(t->val, tval, tlen);
+ t->val[tlen] = L'\0';
+}
+
+Token* Scanner::NextToken() {
+ while (ch == ' ' ||
+-->scan1
+ ) NextCh();
+-->scan2
+ int recKind = noSym;
+ int recEnd = pos;
+ t = CreateToken();
+ t->pos = pos; t->col = col; t->line = line; t->charPos = charPos;
+ int state = start.state(ch);
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t->kind = eofSym; break; } // NextCh already done
+ case 0: {
+ case_0:
+ if (recKind != noSym) {
+ tlen = recEnd - t->pos;
+ SetScannerBehindT();
+ }
+ t->kind = recKind; break;
+ } // NextCh already done
+-->scan3
+ }
+ AppendVal(t);
+ return t;
+}
+
+void Scanner::SetScannerBehindT() {
+ buffer->SetPos(t->pos);
+ NextCh();
+ line = t->line; col = t->col; charPos = t->charPos;
+ for (int i = 0; i < tlen; i++) NextCh();
+}
+
+// get the next token (possibly a token already seen during peeking)
+Token* Scanner::Scan() {
+ if (tokens->next == NULL) {
+ return pt = tokens = NextToken();
+ } else {
+ pt = tokens = tokens->next;
+ return tokens;
+ }
+}
+
+// peek for the next token, ignore pragmas
+Token* Scanner::Peek() {
+ do {
+ if (pt->next == NULL) {
+ pt->next = NextToken();
+ }
+ pt = pt->next;
+ } while (pt->kind > maxT); // skip pragmas
+
+ return pt;
+}
+
+// make sure that peeking starts at the current scan position
+void Scanner::ResetPeek() {
+ pt = tokens;
+}
+
+-->namespace_close
diff --git a/old/cocoo0c/o0c.cpp b/old/cocoo0c/o0c.cpp
new file mode 100644
index 0000000..27b5163
--- /dev/null
+++ b/old/cocoo0c/o0c.cpp
@@ -0,0 +1,24 @@
+#include "Parser.h"
+#include "Scanner.h"
+
+#include <iostream>
+#include <wchar.h>
+
+int main( int argc, char *argv[] )
+{
+ if( argc != 2 ) {
+ std::cerr << "usage: o0c <filename>" << std::endl;
+ return 1;
+ }
+
+ wchar_t *filename = coco_string_create( argv[1] );
+ Oberon0::Scanner *scanner = new Oberon0::Scanner( filename );
+ Oberon0::Parser *parser = new Oberon0::Parser( scanner );
+ parser->Parse( );
+
+ delete parser;
+ delete scanner;
+ coco_string_delete( filename );
+
+ return 0;
+}
diff --git a/old/cocoo0c/test0.o0 b/old/cocoo0c/test0.o0
new file mode 100644
index 0000000..1909c6c
--- /dev/null
+++ b/old/cocoo0c/test0.o0
@@ -0,0 +1 @@
+MODULE Test1;
diff --git a/old/cocoo0c/test1.o0 b/old/cocoo0c/test1.o0
new file mode 100644
index 0000000..ba9ae32
--- /dev/null
+++ b/old/cocoo0c/test1.o0
@@ -0,0 +1,3 @@
+MODULE Test1;
+BEGIN
+END Test2.
diff --git a/old/cocoo0c/test2.o0 b/old/cocoo0c/test2.o0
new file mode 100644
index 0000000..9ea4e63
--- /dev/null
+++ b/old/cocoo0c/test2.o0
@@ -0,0 +1,3 @@
+MODULE Test1;
+BEGIN
+END Test1.
diff --git a/old/cocorepo/Expressions.hpp b/old/cocorepo/Expressions.hpp
new file mode 100644
index 0000000..59e90a5
--- /dev/null
+++ b/old/cocorepo/Expressions.hpp
@@ -0,0 +1,147 @@
+#ifndef EXPRESSIONS_H_
+#define EXPRESSIONS_H_
+
+#include <string>
+#include <map>
+#include <iostream>
+
+using namespace std;
+
+typedef enum {
+ PREDICATE,
+ NOT,
+ AND,
+ OR
+} ExprType;
+
+class Expression {
+ public:
+ virtual bool evaluate( ) = 0;
+ virtual void print( ostream& o ) = 0;
+ virtual ExprType type( ) = 0;
+};
+
+class NotExpression : public Expression {
+ private:
+ Expression *expr;
+
+ public:
+ NotExpression( Expression *_expr )
+ : expr( _expr ) {
+ }
+
+ virtual bool evaluate( ) {
+ return !expr->evaluate( );
+ }
+
+ virtual void print( ostream& o ) {
+ bool is_parent = ( expr->type( ) == AND || expr->type( ) == OR );
+ if( is_parent ) o << "(";
+ o << "NOT ";
+ expr->print( o );
+ if( is_parent ) o << ")";
+ }
+
+ virtual ExprType type( ) {
+ return NOT;
+ }
+};
+
+class AndExpression : public Expression {
+ private:
+ Expression *expr;
+ Expression *right;
+
+ public:
+ AndExpression( Expression *_expr, Expression *_right ) :
+ expr( _expr ), right( _right ) {
+ }
+
+ virtual bool evaluate( ) {
+ return expr->evaluate( ) && right->evaluate( );
+ }
+
+ virtual void print( ostream& o ) {
+ bool is_parent = ( expr->type( ) == OR );
+ if( is_parent ) o << "(";
+ expr->print( o );
+ if( is_parent ) o << ")";
+
+ o << " AND ";
+
+ is_parent = ( expr->type( ) == OR );
+ if( is_parent ) o << "(";
+ right->print( o );
+ if( is_parent ) o << ")";
+ }
+
+ virtual ExprType type( ) {
+ return AND;
+ }
+};
+
+class OrExpression : public Expression {
+ private:
+ Expression *expr;
+ Expression *right;
+
+ public:
+ OrExpression( Expression *_expr, Expression *_right ) :
+ expr( _expr ), right( _right ) {
+ }
+
+ virtual bool evaluate( ) {
+ return expr->evaluate( ) || right->evaluate( );
+ }
+
+ virtual void print( ostream& o ) {
+ expr->print( o );
+ o << " OR ";
+ right->print( o );
+ }
+
+ virtual ExprType type( ) {
+ return OR;
+ }
+};
+
+class Predicate : public Expression {
+ private:
+ string ident;
+
+ public:
+ Predicate( const string _ident )
+ : ident( _ident ) {
+ }
+
+ virtual bool evaluate( ) {
+ return false;
+ }
+
+ virtual void print( ostream& o ) {
+ o << ident;
+ }
+
+ virtual ExprType type( ) {
+ return PREDICATE;
+ }
+};
+
+class Expressions : public Expression {
+ private:
+ typedef map<string,bool> valueMap;
+ valueMap values;
+
+ public:
+ Expressions( Expression *expr ) {
+ }
+
+ void setValue( const string ident, const bool value ) {
+ values[ident] = value;
+ }
+
+ virtual bool evaluate( ) {
+ }
+};
+
+#endif
diff --git a/old/cocorepo/Makefile b/old/cocorepo/Makefile
new file mode 100644
index 0000000..6dcefe4
--- /dev/null
+++ b/old/cocorepo/Makefile
@@ -0,0 +1,25 @@
+all: query
+
+query: Scanner.o Parser.o query.o
+ g++ -o query Scanner.o Parser.o query.o
+
+Parser.o: Parser.cpp Parser.h Expressions.hpp
+Scanner.o: Scanner.cpp Scanner.h Expressions.hpp
+query.o: query.cpp Parser.h Scanner.h Expressions.hpp
+
+Scanner.cpp: Query.atg
+ cococpp -namespace Query Query.atg
+
+test: query
+ @echo "** TEST 0"
+ @cat test0.qry
+ @cat test0.data
+ @./query test0.qry test0.data
+ @echo "** TEST 1"
+ @cat test1.qry
+ @cat test1.data
+ @./query test1.qry test1.data
+
+clean:
+ rm -f query *.old *.o Scanner.h Scanner.cpp Parser.h Parser.cpp
+
diff --git a/old/cocorepo/Parser.frame b/old/cocorepo/Parser.frame
new file mode 100644
index 0000000..d229053
--- /dev/null
+++ b/old/cocorepo/Parser.frame
@@ -0,0 +1,235 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Parser.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_PARSER_H__)
+#define COCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif // !defined(COCO_PARSER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cocorepo/Parser.h b/old/cocorepo/Parser.h
new file mode 100644
index 0000000..59b8b1e
--- /dev/null
+++ b/old/cocorepo/Parser.h
@@ -0,0 +1,203 @@
+
+
+#if !defined(COCO_PARSER_H__)
+#define COCO_PARSER_H__
+
+-->headerdef
+
+#include "Scanner.h"
+
+-->namespace_open
+
+class Errors {
+public:
+ int count; // number of errors detected
+
+ Errors();
+ void SynErr(int line, int col, int n);
+ void Error(int line, int col, const wchar_t *s);
+ void Warning(int line, int col, const wchar_t *s);
+ void Warning(const wchar_t *s);
+ void Exception(const wchar_t *s);
+
+}; // Errors
+
+class Parser {
+private:
+-->constantsheader
+ Token *dummyToken;
+ int errDist;
+ int minErrDist;
+
+ void SynErr(int n);
+ void Get();
+ void Expect(int n);
+ bool StartOf(int s);
+ void ExpectWeak(int n, int follow);
+ bool WeakSeparator(int n, int syFol, int repFol);
+
+public:
+ Scanner *scanner;
+ Errors *errors;
+
+ Token *t; // last recognized token
+ Token *la; // lookahead token
+
+-->declarations
+
+ Parser(Scanner *scanner);
+ ~Parser();
+ void SemErr(const wchar_t* msg);
+
+-->productionsheader
+ void Parse();
+
+}; // end Parser
+
+-->namespace_close
+
+#endif // !defined(COCO_PARSER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Parser.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <wchar.h>
+#include "Parser.h"
+#include "Scanner.h"
+
+
+-->namespace_open
+
+void Parser::SynErr(int n) {
+ if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
+ errDist = 0;
+}
+
+void Parser::SemErr(const wchar_t* msg) {
+ if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
+ errDist = 0;
+}
+
+void Parser::Get() {
+ for (;;) {
+ t = la;
+ la = scanner->Scan();
+ if (la->kind <= maxT) { ++errDist; break; }
+-->pragmas
+ if (dummyToken != t) {
+ dummyToken->kind = t->kind;
+ dummyToken->pos = t->pos;
+ dummyToken->col = t->col;
+ dummyToken->line = t->line;
+ dummyToken->next = NULL;
+ coco_string_delete(dummyToken->val);
+ dummyToken->val = coco_string_create(t->val);
+ t = dummyToken;
+ }
+ la = t;
+ }
+}
+
+void Parser::Expect(int n) {
+ if (la->kind==n) Get(); else { SynErr(n); }
+}
+
+void Parser::ExpectWeak(int n, int follow) {
+ if (la->kind == n) Get();
+ else {
+ SynErr(n);
+ while (!StartOf(follow)) Get();
+ }
+}
+
+bool Parser::WeakSeparator(int n, int syFol, int repFol) {
+ if (la->kind == n) {Get(); return true;}
+ else if (StartOf(repFol)) {return false;}
+ else {
+ SynErr(n);
+ while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
+ Get();
+ }
+ return StartOf(syFol);
+ }
+}
+
+-->productions
+
+void Parser::Parse() {
+ t = NULL;
+ la = dummyToken = new Token();
+ la->val = coco_string_create(L"Dummy Token");
+ Get();
+-->parseRoot
+}
+
+Parser::Parser(Scanner *scanner) {
+-->constants
+ dummyToken = NULL;
+ t = la = NULL;
+ minErrDist = 2;
+ errDist = minErrDist;
+ this->scanner = scanner;
+ errors = new Errors();
+}
+
+bool Parser::StartOf(int s) {
+ const bool T = true;
+ const bool x = false;
+
+-->initialization
+
+ return set[s][la->kind];
+}
+
+Parser::~Parser() {
+ delete errors;
+ delete dummyToken;
+}
+
+Errors::Errors() {
+ count = 0;
+}
+
+void Errors::SynErr(int line, int col, int n) {
+ wchar_t* s;
+ switch (n) {
+-->errors
+ default:
+ {
+ wchar_t format[20];
+ coco_swprintf(format, 20, L"error %d", n);
+ s = coco_string_create(format);
+ }
+ break;
+ }
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ coco_string_delete(s);
+ count++;
+}
+
+void Errors::Error(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+ count++;
+}
+
+void Errors::Warning(int line, int col, const wchar_t *s) {
+ wprintf(L"-- line %d col %d: %ls\n", line, col, s);
+}
+
+void Errors::Warning(const wchar_t *s) {
+ wprintf(L"%ls\n", s);
+}
+
+void Errors::Exception(const wchar_t* s) {
+ wprintf(L"%ls", s);
+ exit(1);
+}
+
+-->namespace_close
diff --git a/old/cocorepo/Query.atg b/old/cocorepo/Query.atg
new file mode 100644
index 0000000..624801b
--- /dev/null
+++ b/old/cocorepo/Query.atg
@@ -0,0 +1,77 @@
+#include <iostream>
+#include <wchar.h>
+#include "Expressions.hpp"
+
+using namespace std;
+
+COMPILER Query
+
+private:
+ Expression *expressions;
+
+public:
+ Expression *getExpressions( ) {
+ return expressions;
+ }
+
+CHARACTERS
+
+ letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
+ digit = "0123456789".
+ cr = '\r'.
+ lf = '\n'.
+ tab = '\t'.
+
+TOKENS
+
+ ident = letter { letter | digit }.
+
+COMMENTS FROM "/*" TO "*/" NESTED
+
+IGNORE cr + lf + tab
+
+PRODUCTIONS
+
+Query (. expressions = 0; .)
+ =
+ [ BinaryExpr<expressions> ]
+ EOF
+ .
+
+BinaryExpr<Expression *&expr> (. expr = 0; Expression *right = 0; .)
+ =
+ NotExpr<expr> { (. bool is_and; .)
+ (
+ "OR" (. is_and = false; .)
+ | "AND" (. is_and = true; .)
+ )
+ NotExpr<right> (.
+ if( is_and ) {
+ expr = new AndExpression( expr, right );
+ } else {
+ expr = new OrExpression( expr, right );
+ }
+ .)
+ }
+ .
+
+NotExpr<Expression *&expr> (. expr = 0; int nots = 0; .)
+ =
+ {
+ "NOT" (. nots++; .)
+ }
+ (
+ "(" BinaryExpr<expr> ")"
+ |
+ ident (.
+ char *ident = coco_string_create_char( t->val );
+ expr = new Predicate( ident );
+ coco_string_delete( ident ); .)
+ ) (.
+ for( int i = 0; i < nots; ++i ) {
+ expr = new NotExpression( expr );
+ }
+ .)
+ .
+
+END Query.
diff --git a/old/cocorepo/Scanner.frame b/old/cocorepo/Scanner.frame
new file mode 100644
index 0000000..71eed98
--- /dev/null
+++ b/old/cocorepo/Scanner.frame
@@ -0,0 +1,896 @@
+/*----------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported to C++ by Csaba Balazs, University of Szeged
+with improvements by Pat Terry, Rhodes University
+
+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.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than
+Coco/R itself) does not fall under the GNU General Public License.
+-----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+Scanner.h Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#if !defined(COCO_SCANNER_H__)
+#define COCO_SCANNER_H__
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// io.h and fcntl are used to ensure binary read from streams on windows
+#if _MSC_VER >= 1300
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if _MSC_VER >= 1400
+#define coco_swprintf swprintf_s
+#elif _MSC_VER >= 1300
+#define coco_swprintf _snwprintf
+#elif defined __MINGW32__
+#define coco_swprintf _snwprintf
+#else
+// assume every other compiler knows swprintf
+#define coco_swprintf swprintf
+#endif
+
+#define COCO_WCHAR_MAX 65535
+#define MIN_BUFFER_LENGTH 1024
+#define MAX_BUFFER_LENGTH (64*MIN_BUFFER_LENGTH)
+#define HEAP_BLOCK_SIZE (64*1024)
+#define COCO_CPP_NAMESPACE_SEPARATOR L':'
+
+// string handling, wide character
+wchar_t* coco_string_create(const wchar_t *value);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex);
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length);
+wchar_t* coco_string_create_upper(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data);
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen);
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2);
+wchar_t* coco_string_create_append(const wchar_t* data, const wchar_t value);
+void coco_string_delete(wchar_t* &data);
+int coco_string_length(const wchar_t* data);
+bool coco_string_endswith(const wchar_t* data, const wchar_t *value);
+int coco_string_indexof(const wchar_t* data, const wchar_t value);
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value);
+void coco_string_merge(wchar_t* &data, const wchar_t* value);
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2);
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2);
+int coco_string_hash(const wchar_t* data);
+
+// string handling, ascii character
+wchar_t* coco_string_create(const char *value);
+char* coco_string_create_char(const wchar_t *value);
+void coco_string_delete(char* &data);
+
+
+-->namespace_open
+
+class Token
+{
+public:
+ int kind; // token kind
+ int pos; // token position in bytes in the source text (starting at 0)
+ int charPos; // token position in characters in the source text (starting at 0)
+ int col; // token column (starting at 1)
+ int line; // token line (starting at 1)
+ wchar_t* val; // token value
+ Token *next; // ML 2005-03-11 Peek tokens are kept in linked list
+
+ Token();
+ ~Token();
+};
+
+class Buffer {
+// This Buffer supports the following cases:
+// 1) seekable stream (file)
+// a) whole stream in buffer
+// b) part of stream in buffer
+// 2) non seekable stream (network, console)
+private:
+ unsigned char *buf; // input buffer
+ int bufCapacity; // capacity of buf
+ int bufStart; // position of first byte in buffer relative to input stream
+ int bufLen; // length of buffer
+ int fileLen; // length of input stream (may change if the stream is no file)
+ int bufPos; // current position in buffer
+ FILE* stream; // input stream (seekable)
+ bool isUserStream; // was the stream opened by the user?
+
+ int ReadNextStreamChunk();
+ bool CanSeek(); // true if stream can be seeked otherwise false
+
+public:
+ static const int EoF = COCO_WCHAR_MAX + 1;
+
+ Buffer(FILE* s, bool isUserStream);
+ Buffer(const unsigned char* buf, int len);
+ Buffer(Buffer *b);
+ virtual ~Buffer();
+
+ virtual void Close();
+ virtual int Read();
+ virtual int Peek();
+ virtual wchar_t* GetString(int beg, int end);
+ virtual int GetPos();
+ virtual void SetPos(int value);
+};
+
+class UTF8Buffer : public Buffer {
+public:
+ UTF8Buffer(Buffer *b) : Buffer(b) {};
+ virtual int Read();
+};
+
+//-----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+//-----------------------------------------------------------------------------------
+class StartStates {
+private:
+ class Elem {
+ public:
+ int key, val;
+ Elem *next;
+ Elem(int key, int val) { this->key = key; this->val = val; next = NULL; }
+ };
+
+ Elem **tab;
+
+public:
+ StartStates() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~StartStates() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(int key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = ((unsigned int) key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int state(int key) {
+ Elem *e = tab[((unsigned int) key) % 128];
+ while (e != NULL && e->key != key) e = e->next;
+ return e == NULL ? 0 : e->val;
+ }
+};
+
+//-------------------------------------------------------------------------------------------
+// KeywordMap -- maps strings to integers (identifiers to keyword kinds)
+//-------------------------------------------------------------------------------------------
+class KeywordMap {
+private:
+ class Elem {
+ public:
+ wchar_t *key;
+ int val;
+ Elem *next;
+ Elem(const wchar_t *key, int val) { this->key = coco_string_create(key); this->val = val; next = NULL; }
+ virtual ~Elem() { coco_string_delete(key); }
+ };
+
+ Elem **tab;
+
+public:
+ KeywordMap() { tab = new Elem*[128]; memset(tab, 0, 128 * sizeof(Elem*)); }
+ virtual ~KeywordMap() {
+ for (int i = 0; i < 128; ++i) {
+ Elem *e = tab[i];
+ while (e != NULL) {
+ Elem *next = e->next;
+ delete e;
+ e = next;
+ }
+ }
+ delete [] tab;
+ }
+
+ void set(const wchar_t *key, int val) {
+ Elem *e = new Elem(key, val);
+ int k = coco_string_hash(key) % 128;
+ e->next = tab[k]; tab[k] = e;
+ }
+
+ int get(const wchar_t *key, int defaultVal) {
+ Elem *e = tab[coco_string_hash(key) % 128];
+ while (e != NULL && !coco_string_equal(e->key, key)) e = e->next;
+ return e == NULL ? defaultVal : e->val;
+ }
+};
+
+class Scanner {
+private:
+ void *firstHeap;
+ void *heap;
+ void *heapTop;
+ void **heapEnd;
+
+ unsigned char EOL;
+ int eofSym;
+ int noSym;
+ int maxT;
+ int charSetSize;
+ StartStates start;
+ KeywordMap keywords;
+
+ Token *t; // current token
+ wchar_t *tval; // text of current token
+ int tvalLength; // length of text of current token
+ int tlen; // length of current token
+
+ Token *tokens; // list of tokens already peeked (first token is a dummy)
+ Token *pt; // current peek token
+
+ int ch; // current input character
+-->casing0
+ int pos; // byte position of current character
+ int charPos; // position by unicode characters starting with 0
+ int line; // line number of current character
+ int col; // column number of current character
+ int oldEols; // EOLs that appeared in a comment;
+
+ void CreateHeapBlock();
+ Token* CreateToken();
+ void AppendVal(Token *t);
+ void SetScannerBehindT();
+
+ void Init();
+ void NextCh();
+ void AddCh();
+-->commentsheader
+ Token* NextToken();
+
+public:
+ Buffer *buffer; // scanner buffer
+
+ Scanner(const unsigned char* buf, int len);
+ Scanner(const wchar_t* fileName);
+ Scanner(FILE* s);
+ ~Scanner();
+ Token* Scan();
+ Token* Peek();
+ void ResetPeek();
+
+}; // end Scanner
+
+-->namespace_close
+
+#endif // !defined(COCO_SCANNER_H__)
+
+-->implementation
+
+/*----------------------------------------------------------------------
+Scanner.cpp Specification
+-----------------------------------------------------------------------*/
+
+-->begin
+
+#include <memory.h>
+#include <string.h>
+#include "Scanner.h"
+
+// string handling, wide character
+
+
+wchar_t* coco_string_create(const wchar_t* value) {
+ return coco_string_create(value, 0);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex) {
+ int valueLen = 0;
+ int len = 0;
+
+ if (value) {
+ valueLen = wcslen(value);
+ len = valueLen - startIndex;
+ }
+
+ return coco_string_create(value, startIndex, len);
+}
+
+wchar_t* coco_string_create(const wchar_t *value, int startIndex, int length) {
+ int len = 0;
+ wchar_t* data;
+
+ if (value) { len = length; }
+ data = new wchar_t[len + 1];
+ wcsncpy(data, &(value[startIndex]), len);
+ data[len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_upper(const wchar_t* data) {
+ if (!data) { return NULL; }
+
+ int dataLen = 0;
+ if (data) { dataLen = wcslen(data); }
+
+ wchar_t *newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ if ((L'a' <= data[i]) && (data[i] <= L'z')) {
+ newData[i] = data[i] + (L'A' - L'a');
+ }
+ else { newData[i] = data[i]; }
+ }
+
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data) {
+ if (!data) { return NULL; }
+ int dataLen = wcslen(data);
+ return coco_string_create_lower(data, 0, dataLen);
+}
+
+wchar_t* coco_string_create_lower(const wchar_t* data, int startIndex, int dataLen) {
+ if (!data) { return NULL; }
+
+ wchar_t* newData = new wchar_t[dataLen + 1];
+
+ for (int i = 0; i <= dataLen; i++) {
+ wchar_t ch = data[startIndex + i];
+ if ((L'A' <= ch) && (ch <= L'Z')) {
+ newData[i] = ch - (L'A' - L'a');
+ }
+ else { newData[i] = ch; }
+ }
+ newData[dataLen] = L'\0';
+ return newData;
+}
+
+wchar_t* coco_string_create_append(const wchar_t* data1, const wchar_t* data2) {
+ wchar_t* data;
+ int data1Len = 0;
+ int data2Len = 0;
+
+ if (data1) { data1Len = wcslen(data1); }
+ if (data2) {data2Len = wcslen(data2); }
+
+ data = new wchar_t[data1Len + data2Len + 1];
+
+ if (data1) { wcscpy(data, data1); }
+ if (data2) { wcscpy(data + data1Len, data2); }
+
+ data[data1Len + data2Len] = 0;
+
+ return data;
+}
+
+wchar_t* coco_string_create_append(const wchar_t *target, const wchar_t appendix) {
+ int targetLen = coco_string_length(target);
+ wchar_t* data = new wchar_t[targetLen + 2];
+ wcsncpy(data, target, targetLen);
+ data[targetLen] = appendix;
+ data[targetLen + 1] = 0;
+ return data;
+}
+
+void coco_string_delete(wchar_t* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+int coco_string_length(const wchar_t* data) {
+ if (data) { return wcslen(data); }
+ return 0;
+}
+
+bool coco_string_endswith(const wchar_t* data, const wchar_t *end) {
+ int dataLen = wcslen(data);
+ int endLen = wcslen(end);
+ return (endLen <= dataLen) && (wcscmp(data + dataLen - endLen, end) == 0);
+}
+
+int coco_string_indexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcschr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+int coco_string_lastindexof(const wchar_t* data, const wchar_t value) {
+ const wchar_t* chr = wcsrchr(data, value);
+
+ if (chr) { return (chr-data); }
+ return -1;
+}
+
+void coco_string_merge(wchar_t* &target, const wchar_t* appendix) {
+ if (!appendix) { return; }
+ wchar_t* data = coco_string_create_append(target, appendix);
+ delete [] target;
+ target = data;
+}
+
+bool coco_string_equal(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp( data1, data2 ) == 0;
+}
+
+int coco_string_compareto(const wchar_t* data1, const wchar_t* data2) {
+ return wcscmp(data1, data2);
+}
+
+int coco_string_hash(const wchar_t *data) {
+ int h = 0;
+ if (!data) { return 0; }
+ while (*data != 0) {
+ h = (h * 7) ^ *data;
+ ++data;
+ }
+ if (h < 0) { h = -h; }
+ return h;
+}
+
+// string handling, ascii character
+
+wchar_t* coco_string_create(const char* value) {
+ int len = 0;
+ if (value) { len = strlen(value); }
+ wchar_t* data = new wchar_t[len + 1];
+ for (int i = 0; i < len; ++i) { data[i] = (wchar_t) value[i]; }
+ data[len] = 0;
+ return data;
+}
+
+char* coco_string_create_char(const wchar_t *value) {
+ int len = coco_string_length(value);
+ char *res = new char[len + 1];
+ for (int i = 0; i < len; ++i) { res[i] = (char) value[i]; }
+ res[len] = 0;
+ return res;
+}
+
+void coco_string_delete(char* &data) {
+ delete [] data;
+ data = NULL;
+}
+
+
+-->namespace_open
+
+Token::Token() {
+ kind = 0;
+ pos = 0;
+ col = 0;
+ line = 0;
+ val = NULL;
+ next = NULL;
+}
+
+Token::~Token() {
+ coco_string_delete(val);
+}
+
+Buffer::Buffer(FILE* s, bool isUserStream) {
+// ensure binary read on windows
+#if _MSC_VER >= 1300
+ _setmode(_fileno(s), _O_BINARY);
+#endif
+ stream = s; this->isUserStream = isUserStream;
+ if (CanSeek()) {
+ fseek(s, 0, SEEK_END);
+ fileLen = ftell(s);
+ fseek(s, 0, SEEK_SET);
+ bufLen = (fileLen < MAX_BUFFER_LENGTH) ? fileLen : MAX_BUFFER_LENGTH;
+ bufStart = INT_MAX; // nothing in the buffer so far
+ } else {
+ fileLen = bufLen = bufStart = 0;
+ }
+ bufCapacity = (bufLen>0) ? bufLen : MIN_BUFFER_LENGTH;
+ buf = new unsigned char[bufCapacity];
+ if (fileLen > 0) SetPos(0); // setup buffer to position 0 (start)
+ else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid
+ if (bufLen == fileLen && CanSeek()) Close();
+}
+
+Buffer::Buffer(Buffer *b) {
+ buf = b->buf;
+ bufCapacity = b->bufCapacity;
+ b->buf = NULL;
+ bufStart = b->bufStart;
+ bufLen = b->bufLen;
+ fileLen = b->fileLen;
+ bufPos = b->bufPos;
+ stream = b->stream;
+ b->stream = NULL;
+ isUserStream = b->isUserStream;
+}
+
+Buffer::Buffer(const unsigned char* buf, int len) {
+ this->buf = new unsigned char[len];
+ memcpy(this->buf, buf, len*sizeof(unsigned char));
+ bufStart = 0;
+ bufCapacity = bufLen = len;
+ fileLen = len;
+ bufPos = 0;
+ stream = NULL;
+}
+
+Buffer::~Buffer() {
+ Close();
+ if (buf != NULL) {
+ delete [] buf;
+ buf = NULL;
+ }
+}
+
+void Buffer::Close() {
+ if (!isUserStream && stream != NULL) {
+ fclose(stream);
+ stream = NULL;
+ }
+}
+
+int Buffer::Read() {
+ if (bufPos < bufLen) {
+ return buf[bufPos++];
+ } else if (GetPos() < fileLen) {
+ SetPos(GetPos()); // shift buffer start to Pos
+ return buf[bufPos++];
+ } else if ((stream != NULL) && !CanSeek() && (ReadNextStreamChunk() > 0)) {
+ return buf[bufPos++];
+ } else {
+ return EoF;
+ }
+}
+
+int Buffer::Peek() {
+ int curPos = GetPos();
+ int ch = Read();
+ SetPos(curPos);
+ return ch;
+}
+
+// beg .. begin, zero-based, inclusive, in byte
+// end .. end, zero-based, exclusive, in byte
+wchar_t* Buffer::GetString(int beg, int end) {
+ int len = 0;
+ wchar_t *buf = new wchar_t[end - beg];
+ int oldPos = GetPos();
+ SetPos(beg);
+ while (GetPos() < end) buf[len++] = (wchar_t) Read();
+ SetPos(oldPos);
+ wchar_t *res = coco_string_create(buf, 0, len);
+ coco_string_delete(buf);
+ return res;
+}
+
+int Buffer::GetPos() {
+ return bufPos + bufStart;
+}
+
+void Buffer::SetPos(int value) {
+ if ((value >= fileLen) && (stream != NULL) && !CanSeek()) {
+ // Wanted position is after buffer and the stream
+ // is not seek-able e.g. network or console,
+ // thus we have to read the stream manually till
+ // the wanted position is in sight.
+ while ((value >= fileLen) && (ReadNextStreamChunk() > 0));
+ }
+
+ if ((value < 0) || (value > fileLen)) {
+ wprintf(L"--- buffer out of bounds access, position: %d\n", value);
+ exit(1);
+ }
+
+ if ((value >= bufStart) && (value < (bufStart + bufLen))) { // already in buffer
+ bufPos = value - bufStart;
+ } else if (stream != NULL) { // must be swapped in
+ fseek(stream, value, SEEK_SET);
+ bufLen = fread(buf, sizeof(unsigned char), bufCapacity, stream);
+ bufStart = value; bufPos = 0;
+ } else {
+ bufPos = fileLen - bufStart; // make Pos return fileLen
+ }
+}
+
+// Read the next chunk of bytes from the stream, increases the buffer
+// if needed and updates the fields fileLen and bufLen.
+// Returns the number of bytes read.
+int Buffer::ReadNextStreamChunk() {
+ int free = bufCapacity - bufLen;
+ if (free == 0) {
+ // in the case of a growing input stream
+ // we can neither seek in the stream, nor can we
+ // foresee the maximum length, thus we must adapt
+ // the buffer size on demand.
+ bufCapacity = bufLen * 2;
+ unsigned char *newBuf = new unsigned char[bufCapacity];
+ memcpy(newBuf, buf, bufLen*sizeof(unsigned char));
+ delete [] buf;
+ buf = newBuf;
+ free = bufLen;
+ }
+ int read = fread(buf + bufLen, sizeof(unsigned char), free, stream);
+ if (read > 0) {
+ fileLen = bufLen = (bufLen + read);
+ return read;
+ }
+ // end of stream reached
+ return 0;
+}
+
+bool Buffer::CanSeek() {
+ return (stream != NULL) && (ftell(stream) != -1);
+}
+
+int UTF8Buffer::Read() {
+ int ch;
+ do {
+ ch = Buffer::Read();
+ // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+ } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EoF));
+ if (ch < 128 || ch == EoF) {
+ // nothing to do, first 127 chars are the same in ascii and utf8
+ // 0xxxxxxx or end of file character
+ } else if ((ch & 0xF0) == 0xF0) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x07; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F; ch = Buffer::Read();
+ int c4 = ch & 0x3F;
+ ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+ } else if ((ch & 0xE0) == 0xE0) {
+ // 1110xxxx 10xxxxxx 10xxxxxx
+ int c1 = ch & 0x0F; ch = Buffer::Read();
+ int c2 = ch & 0x3F; ch = Buffer::Read();
+ int c3 = ch & 0x3F;
+ ch = (((c1 << 6) | c2) << 6) | c3;
+ } else if ((ch & 0xC0) == 0xC0) {
+ // 110xxxxx 10xxxxxx
+ int c1 = ch & 0x1F; ch = Buffer::Read();
+ int c2 = ch & 0x3F;
+ ch = (c1 << 6) | c2;
+ }
+ return ch;
+}
+
+Scanner::Scanner(const unsigned char* buf, int len) {
+ buffer = new Buffer(buf, len);
+ Init();
+}
+
+Scanner::Scanner(const wchar_t* fileName) {
+ FILE* stream;
+ char *chFileName = coco_string_create_char(fileName);
+ if ((stream = fopen(chFileName, "rb")) == NULL) {
+ wprintf(L"--- Cannot open file %ls\n", fileName);
+ exit(1);
+ }
+ coco_string_delete(chFileName);
+ buffer = new Buffer(stream, false);
+ Init();
+}
+
+Scanner::Scanner(FILE* s) {
+ buffer = new Buffer(s, true);
+ Init();
+}
+
+Scanner::~Scanner() {
+ char* cur = (char*) firstHeap;
+
+ while(cur != NULL) {
+ cur = *(char**) (cur + HEAP_BLOCK_SIZE);
+ free(firstHeap);
+ firstHeap = cur;
+ }
+ delete [] tval;
+ delete buffer;
+}
+
+void Scanner::Init() {
+ EOL = '\n';
+ eofSym = 0;
+-->declarations
+
+ tvalLength = 128;
+ tval = new wchar_t[tvalLength]; // text of current token
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ heap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ firstHeap = heap;
+ heapEnd = (void**) (((char*) heap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heapTop = heap;
+ if (sizeof(Token) > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too small HEAP_BLOCK_SIZE\n");
+ exit(1);
+ }
+
+ pos = -1; line = 1; col = 0; charPos = -1;
+ oldEols = 0;
+ NextCh();
+ if (ch == 0xEF) { // check optional byte order mark for UTF-8
+ NextCh(); int ch1 = ch;
+ NextCh(); int ch2 = ch;
+ if (ch1 != 0xBB || ch2 != 0xBF) {
+ wprintf(L"Illegal byte order mark at start of file");
+ exit(1);
+ }
+ Buffer *oldBuf = buffer;
+ buffer = new UTF8Buffer(buffer); col = 0; charPos = -1;
+ delete oldBuf; oldBuf = NULL;
+ NextCh();
+ }
+
+-->initialization
+ pt = tokens = CreateToken(); // first token is a dummy
+}
+
+void Scanner::NextCh() {
+ if (oldEols > 0) { ch = EOL; oldEols--; }
+ else {
+ pos = buffer->GetPos();
+ // buffer reads unicode chars, if UTF8 has been detected
+ ch = buffer->Read(); col++; charPos++;
+ // replace isolated '\r' by '\n' in order to make
+ // eol handling uniform across Windows, Unix and Mac
+ if (ch == L'\r' && buffer->Peek() != L'\n') ch = EOL;
+ if (ch == EOL) { line++; col = 0; }
+ }
+-->casing1
+}
+
+void Scanner::AddCh() {
+ if (tlen >= tvalLength) {
+ tvalLength *= 2;
+ wchar_t *newBuf = new wchar_t[tvalLength];
+ memcpy(newBuf, tval, tlen*sizeof(wchar_t));
+ delete [] tval;
+ tval = newBuf;
+ }
+ if (ch != Buffer::EoF) {
+-->casing2
+ NextCh();
+ }
+}
+
+-->comments
+
+void Scanner::CreateHeapBlock() {
+ void* newHeap;
+ char* cur = (char*) firstHeap;
+
+ while(((char*) tokens < cur) || ((char*) tokens > (cur + HEAP_BLOCK_SIZE))) {
+ cur = *((char**) (cur + HEAP_BLOCK_SIZE));
+ free(firstHeap);
+ firstHeap = cur;
+ }
+
+ // HEAP_BLOCK_SIZE byte heap + pointer to next heap block
+ newHeap = malloc(HEAP_BLOCK_SIZE + sizeof(void*));
+ *heapEnd = newHeap;
+ heapEnd = (void**) (((char*) newHeap) + HEAP_BLOCK_SIZE);
+ *heapEnd = 0;
+ heap = newHeap;
+ heapTop = heap;
+}
+
+Token* Scanner::CreateToken() {
+ Token *t;
+ if (((char*) heapTop + (int) sizeof(Token)) >= (char*) heapEnd) {
+ CreateHeapBlock();
+ }
+ t = (Token*) heapTop;
+ heapTop = (void*) ((char*) heapTop + sizeof(Token));
+ t->val = NULL;
+ t->next = NULL;
+ return t;
+}
+
+void Scanner::AppendVal(Token *t) {
+ int reqMem = (tlen + 1) * sizeof(wchar_t);
+ if (((char*) heapTop + reqMem) >= (char*) heapEnd) {
+ if (reqMem > HEAP_BLOCK_SIZE) {
+ wprintf(L"--- Too long token value\n");
+ exit(1);
+ }
+ CreateHeapBlock();
+ }
+ t->val = (wchar_t*) heapTop;
+ heapTop = (void*) ((char*) heapTop + reqMem);
+
+ wcsncpy(t->val, tval, tlen);
+ t->val[tlen] = L'\0';
+}
+
+Token* Scanner::NextToken() {
+ while (ch == ' ' ||
+-->scan1
+ ) NextCh();
+-->scan2
+ int recKind = noSym;
+ int recEnd = pos;
+ t = CreateToken();
+ t->pos = pos; t->col = col; t->line = line; t->charPos = charPos;
+ int state = start.state(ch);
+ tlen = 0; AddCh();
+
+ switch (state) {
+ case -1: { t->kind = eofSym; break; } // NextCh already done
+ case 0: {
+ case_0:
+ if (recKind != noSym) {
+ tlen = recEnd - t->pos;
+ SetScannerBehindT();
+ }
+ t->kind = recKind; break;
+ } // NextCh already done
+-->scan3
+ }
+ AppendVal(t);
+ return t;
+}
+
+void Scanner::SetScannerBehindT() {
+ buffer->SetPos(t->pos);
+ NextCh();
+ line = t->line; col = t->col; charPos = t->charPos;
+ for (int i = 0; i < tlen; i++) NextCh();
+}
+
+// get the next token (possibly a token already seen during peeking)
+Token* Scanner::Scan() {
+ if (tokens->next == NULL) {
+ return pt = tokens = NextToken();
+ } else {
+ pt = tokens = tokens->next;
+ return tokens;
+ }
+}
+
+// peek for the next token, ignore pragmas
+Token* Scanner::Peek() {
+ do {
+ if (pt->next == NULL) {
+ pt->next = NextToken();
+ }
+ pt = pt->next;
+ } while (pt->kind > maxT); // skip pragmas
+
+ return pt;
+}
+
+// make sure that peeking starts at the current scan position
+void Scanner::ResetPeek() {
+ pt = tokens;
+}
+
+-->namespace_close
diff --git a/old/cocorepo/query.cpp b/old/cocorepo/query.cpp
new file mode 100644
index 0000000..3f0bedd
--- /dev/null
+++ b/old/cocorepo/query.cpp
@@ -0,0 +1,29 @@
+#include "Parser.h"
+#include "Scanner.h"
+
+#include <iostream>
+#include <wchar.h>
+
+int main( int argc, char *argv[] )
+{
+ if( argc != 3 ) {
+ std::cerr << "usage: query <expression file> <data file>" << std::endl;
+ return 1;
+ }
+
+ wchar_t *expression_filename = coco_string_create( argv[1] );
+ Query::Scanner *scanner = new Query::Scanner( expression_filename );
+ Query::Parser *parser = new Query::Parser( scanner );
+ parser->Parse( );
+ Expression *expr = parser->getExpressions( );
+ expr->print( cout );
+ cout << endl;
+
+// wchar_t *data_filename =
+
+ delete parser;
+ delete scanner;
+ coco_string_delete( expression_filename );
+
+ return 0;
+}
diff --git a/old/cocorepo/test0.data b/old/cocorepo/test0.data
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/old/cocorepo/test0.data
diff --git a/old/cocorepo/test0.qry b/old/cocorepo/test0.qry
new file mode 100644
index 0000000..4c541c8
--- /dev/null
+++ b/old/cocorepo/test0.qry
@@ -0,0 +1,3 @@
+/* test 0 */
+
+(flu AND fla) OR NOT bla
diff --git a/old/cocorepo/test1.data b/old/cocorepo/test1.data
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/old/cocorepo/test1.data
diff --git a/old/cocorepo/test1.qry b/old/cocorepo/test1.qry
new file mode 100644
index 0000000..b82d6be
--- /dev/null
+++ b/old/cocorepo/test1.qry
@@ -0,0 +1,3 @@
+/* test 0 */
+
+(flu OR fla) AND (blu OR bla)
diff --git a/old/ebnf.c b/old/ebnf.c
new file mode 100644
index 0000000..724cec2
--- /dev/null
+++ b/old/ebnf.c
@@ -0,0 +1,274 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+
+#define MAXLEN 80
+
+typedef enum {
+ undef,
+ eof,
+ error,
+ identifier,
+ literal,
+ dot,
+ eql,
+ lparen,
+ rparen,
+ lbrak,
+ rbrak,
+ lbrace,
+ rbrace,
+ bar
+} Sym;
+
+typedef struct {
+ Sym sym;
+ char value[MAXLEN];
+} Symbol;
+
+typedef struct {
+ int line;
+ int col;
+ FILE *f;
+} Scanner;
+
+static int get_char( Scanner *scan ) {
+ int c = getc( scan->f );
+ scan->col++;
+ if( c == '\n' ) {
+ scan->line++;
+ scan->col = 1;
+ }
+ return c;
+}
+
+static void unget_char( Scanner *scan, int c ) {
+ ungetc( c, scan->f );
+ scan->col--;
+}
+
+static Symbol skip_blanks( Scanner *scan ) {
+ int c;
+ Symbol s;
+
+ while( ( c = get_char( scan ) ) != EOF && iscntrl( c ) || ( c == ' ' ) );
+
+ if( c == EOF ) {
+ s.sym = eof;
+ return s;
+ }
+
+ unget_char( scan, c );
+
+ s.sym = undef;
+ return s;
+}
+
+static int is_letter( char c ) {
+ return( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) );
+}
+
+static int is_digit( char c ) {
+ return( c >= '0' && c <= '9' );
+}
+
+static Symbol get_sym( Scanner *scan ) {
+ int c;
+ Symbol s;
+ int i;
+
+ s.sym = undef;
+
+ s = skip_blanks( scan );
+ if( s.sym == eof ) return s;
+
+ c = get_char( scan );
+ if( c == EOF ) {
+ s.sym = EOF;
+ return s;
+ }
+ unget_char( scan, c );
+
+ if( is_letter( c ) ) {
+ i = 0;
+ s.sym = identifier;
+ while( ( c = get_char( scan ) ) != EOF && ( is_letter( c ) || c == '-' ) ) {
+ s.value[i++] = c;
+ }
+ s.value[i] = '\0';
+ } else if( c == '\"' ) {
+ int escaped = 0;
+ i = 0;
+ s.sym = literal;
+ (void)get_char( scan ); /* skip first quote */
+ while( ( c = get_char( scan ) ) != EOF && c != '\"' || escaped ) {
+ if( c == '\\' ) {
+ escaped = 1;
+ } else {
+ s.value[i++] = c;
+ escaped = 0;
+ }
+ }
+ s.value[i] = '\0';
+ /* ensure we end in a quote */
+ if( c != '\"' ) {
+ fprintf( stderr, "ERROR(%d:%d): Unbalanced quote after literal '%s'\n",
+ scan->line, scan->col, s.value );
+ s.sym = error;
+ return s;
+ }
+ } else if( c == '=' ) {
+ c = get_char( scan );
+ s.sym = eql;
+ } else if( c == '(' ) {
+ c = get_char( scan );
+ s.sym = lparen;
+ } else if( c == ')' ) {
+ c = get_char( scan );
+ s.sym = rparen;
+ } else if( c == '[' ) {
+ c = get_char( scan );
+ s.sym = lbrak;
+ } else if( c == ']' ) {
+ c = get_char( scan );
+ s.sym = rbrak;
+ } else if( c == '{' ) {
+ c = get_char( scan );
+ s.sym = lbrace;
+ } else if( c == '}' ) {
+ c = get_char( scan );
+ s.sym = rbrace;
+ } else if( c == '|' ) {
+ c = get_char( scan );
+ s.sym = bar;
+ } else if( c == '.' ) {
+ c = get_char( scan );
+ s.sym = dot;
+ } else {
+ c = get_char( scan );
+ s.sym = error;
+ }
+
+ return s;
+}
+
+static Scanner init_scanner( FILE *f )
+{
+ Scanner s;
+
+ s.line = 1;
+ s.col = 1;
+ s.f = f;
+
+ return s;
+}
+
+static void Expression( Scanner *scan, Symbol *s );
+
+static void Factor( Scanner *scan, Symbol *s )
+{
+ if( s->sym == identifier ) {
+ printf( "ident: %s\n", s->value );
+ *s = get_sym( scan );
+ } else if( s->sym == literal ) {
+ printf( "literal: %s\n", s->value );
+ *s = get_sym( scan );
+ } else if( s->sym == lparen ) {
+ *s = get_sym( scan );
+ Expression( scan, s );
+ if( s->sym == rparen ) {
+ *s = get_sym( scan );
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Expected ')' after expression\n",
+ scan->line, scan->col );
+ }
+ } else if( s->sym == lbrak ) {
+ *s = get_sym( scan );
+ Expression( scan, s );
+ if( s->sym == rbrak ) {
+ *s = get_sym( scan );
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Expected ']' after expression\n",
+ scan->line, scan->col );
+ }
+ } else if( s->sym == lbrace ) {
+ *s = get_sym( scan );
+ Expression( scan, s );
+ if( s->sym == rbrace ) {
+ *s = get_sym( scan );
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Expected ']' after expression\n",
+ scan->line, scan->col );
+ }
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Unexpected symbol '%d' in factor\n",
+ scan->line, scan->col, s->sym );
+ }
+}
+
+static void Term( Scanner *scan, Symbol *s )
+{
+ Factor( scan, s );
+ while( s->sym != bar && s->sym != rparen && s->sym != rbrace && s->sym != rbrak && s->sym != dot ) {
+ Factor( scan, s );
+ }
+}
+
+static void Expression( Scanner *scan, Symbol *s )
+{
+ Term( scan, s );
+ while( s->sym == bar ) {
+ *s = get_sym( scan );
+ Term( scan, s );
+ }
+}
+
+static void Production( Scanner *scan, Symbol *s )
+{
+ assert( s->sym == identifier );
+ *s = get_sym( scan );
+ if( s->sym == eql ) {
+ *s = get_sym( scan );
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Excepted '=' after identifier\n",
+ scan->line, scan->col );
+ }
+
+ Expression( scan, s );
+
+ if( s->sym == dot ) {
+ *s = get_sym( scan );
+ } else {
+ fprintf( stderr, "ERROR(%d:%d): Expected '.' after expression\n",
+ scan->line, scan->col );
+ }
+}
+
+static void Syntax( Scanner *scan, Symbol *s )
+{
+ while( s->sym == identifier ) {
+ Production( scan, s );
+ }
+}
+
+static void Compile( Scanner *scan )
+{
+ Symbol s;
+
+ do {
+ s = get_sym( scan );
+ if( s.sym == eof ) continue;
+ Syntax( scan, &s );
+ } while( s.sym != eof );
+}
+
+int main( void )
+{
+ Scanner scan;
+
+ scan = init_scanner( stdin );
+
+ Compile( &scan );
+ return 0;
+}
+
diff --git a/old/llvmtests/LINKS b/old/llvmtests/LINKS
new file mode 100644
index 0000000..41044ca
--- /dev/null
+++ b/old/llvmtests/LINKS
@@ -0,0 +1,2 @@
+http://www.ibm.com/developerworks/opensource/library/l-flexbison/index.html
+http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/
diff --git a/old/llvmtests/README b/old/llvmtests/README
new file mode 100644
index 0000000..8de04b8
--- /dev/null
+++ b/old/llvmtests/README
@@ -0,0 +1,5 @@
+clang -o hello.l -I../../include/wolf -Os -S -emit-llvm hello.c
+opt -S hello.s > hello-opt.s
+xxdiff hello.s hello-opt.s
+llc -O0 hello.l -march=x86-64 -p hello-amd64.s
+llc -O0 hello.l -march=mipsel -o hello-mipsel.s
diff --git a/old/llvmtests/hello.c b/old/llvmtests/hello.c
new file mode 100644
index 0000000..a08b0c2
--- /dev/null
+++ b/old/llvmtests/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main( void )
+{
+ puts( "hello" );
+ return 0;
+}
diff --git a/old/parser.c b/old/parser.c
new file mode 100644
index 0000000..79a7905
--- /dev/null
+++ b/old/parser.c
@@ -0,0 +1,180 @@
+#include <stdio.h>
+#include <ctype.h>
+
+#define MAXLEN 80
+
+typedef enum {
+ undef,
+ eof,
+ error,
+ identifier,
+ literal,
+ dot,
+ eql,
+ lparen,
+ rparen,
+ lbrak,
+ rbrak,
+ lbrace,
+ rbrace,
+ bar
+} Sym;
+
+typedef struct {
+ Sym sym;
+ char value[MAXLEN];
+} Symbol;
+
+typedef struct {
+ int line;
+ int col;
+ FILE *f;
+} Scanner;
+
+static int get_char( Scanner *scan ) {
+ int c = getc( scan->f );
+ scan->col++;
+ if( c == '\n' ) {
+ scan->line++;
+ scan->col = 1;
+ }
+ return c;
+}
+
+static void unget_char( Scanner *scan, int c ) {
+ ungetc( c, scan->f );
+ scan->col--;
+}
+
+static Symbol skip_blanks( Scanner *scan ) {
+ int c;
+ Symbol s;
+
+ while( ( c = get_char( scan ) ) != EOF && iscntrl( c ) || ( c == ' ' ) );
+
+ if( c == EOF ) {
+ s.sym = eof;
+ return s;
+ }
+
+ unget_char( scan, c );
+
+ s.sym = undef;
+ return s;
+}
+
+static int is_letter( char c ) {
+ return( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) );
+}
+
+static int is_digit( char c ) {
+ return( c >= '0' && c <= '9' );
+}
+
+static Symbol get_sym( Scanner *scan ) {
+ int c;
+ Symbol s;
+ int i;
+
+ s.sym = undef;
+
+ s = skip_blanks( scan );
+ if( s.sym == eof ) return s;
+
+ c = get_char( scan );
+ if( c == EOF ) {
+ s.sym = EOF;
+ return s;
+ }
+ unget_char( scan, c );
+
+ if( is_letter( c ) ) {
+ i = 0;
+ s.sym = identifier;
+ while( ( c = get_char( scan ) ) != EOF && is_letter( c ) ) {
+ s.value[i++] = c;
+ }
+ s.value[i] = '\0';
+ printf( "(%d:%d): ident '%s'\n", scan->line, scan->col, s.value );
+ } else if( c == '\"' ) {
+ int escaped = 0;
+ i = 0;
+ s.sym = literal;
+ (void)get_char( scan ); /* skip first quote */
+ while( ( c = get_char( scan ) ) != EOF && c != '\"' || escaped ) {
+ if( c == '\\' ) {
+ escaped = 1;
+ } else {
+ s.value[i++] = c;
+ escaped = 0;
+ }
+ }
+ s.value[i] = '\0';
+ /* ensure we end in a quote */
+ if( c != '\"' ) {
+ fprintf( stderr, "ERROR(%d:%d): Unbalanced quote after literal '%s'\n",
+ scan->line, scan->col, s.value );
+ s.sym = error;
+ return s;
+ }
+ printf( "(%d:%d): literal '%s'\n", scan->line, scan->col, s.value );
+ } else if( c == '=' ) {
+ c = get_char( scan );
+ s.sym = eql;
+ } else if( c == '(' ) {
+ c = get_char( scan );
+ s.sym = lparen;
+ } else if( c == ')' ) {
+ c = get_char( scan );
+ s.sym = rparen;
+ } else if( c == '[' ) {
+ c = get_char( scan );
+ s.sym = lbrak;
+ } else if( c == ']' ) {
+ c = get_char( scan );
+ s.sym = rbrak;
+ } else if( c == '{' ) {
+ c = get_char( scan );
+ s.sym = lbrace;
+ } else if( c == '}' ) {
+ c = get_char( scan );
+ s.sym = rbrace;
+ } else if( c == '|' ) {
+ c = get_char( scan );
+ s.sym = bar;
+ } else if( c == '.' ) {
+ c = get_char( scan );
+ s.sym = dot;
+ } else {
+ c = get_char( scan );
+ s.sym = error;
+ }
+
+ return s;
+}
+
+static Scanner init_scanner( FILE *f )
+{
+ Scanner s;
+
+ s.line = 1;
+ s.col = 1;
+ s.f = f;
+
+ return s;
+}
+
+int main( void )
+{
+ Symbol s;
+ Scanner scan;
+
+ scan = init_scanner( stdin );
+
+ do {
+ s = get_sym( &scan );
+ if( s.sym == eof ) continue;
+ } while( s.sym != eof );
+
+ return 0;
+}
diff --git a/old/test1.ebnf b/old/test1.ebnf
new file mode 100644
index 0000000..a100d4f
--- /dev/null
+++ b/old/test1.ebnf
@@ -0,0 +1,5 @@
+Syntax = { Production } .
+Production = Identifier "=" Expression "." .
+Expression = Term { "|" Term } .
+Term = Factor { Factor } .
+Factor = Identifier | String | "(" Expression ")" | "[" Expression "]" | "{" Expression "}".
diff --git a/old/test2.ebnf b/old/test2.ebnf
new file mode 100644
index 0000000..b19b358
--- /dev/null
+++ b/old/test2.ebnf
@@ -0,0 +1,5 @@
+Identifier = Letter { Letter | Digit } .
+Literal = "\"" { Letter | Digit } "\"".
+Integer = Digit { Digit }.
+Letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z".
+Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
diff --git a/old/test3.ebnf b/old/test3.ebnf
new file mode 100644
index 0000000..d107fec
--- /dev/null
+++ b/old/test3.ebnf
@@ -0,0 +1,3 @@
+Expression = Term { ( "+" | "-" ) Term } .
+Term = Factor { ( "*" | "/" ) Factor } .
+Factor = Identifier | "(" Expression ")" .
diff --git a/old/toy/LINKS b/old/toy/LINKS
new file mode 100644
index 0000000..69ae0b3
--- /dev/null
+++ b/old/toy/LINKS
@@ -0,0 +1,2 @@
+http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/
+http://llvm.org/releases/3.3/docs/tutorial/LangImpl3.html
diff --git a/old/toy/Makefile b/old/toy/Makefile
new file mode 100644
index 0000000..031f04d
--- /dev/null
+++ b/old/toy/Makefile
@@ -0,0 +1,44 @@
+all: main
+
+CXXFLAGS = $(shell llvm-config --cppflags)
+LDFLAGS = $(shell llvm-config --ldflags)
+LIBS = $(shell llvm-config --libs)
+
+CXX ?= g++
+
+main: main.o lex.grammar.o grammar.o node.o codegen.o
+ $(CXX) -o main main.o lex.grammar.o grammar.o node.o codegen.o $(LDFLAGS) $(LIBS)
+
+main.o: main.cpp node.hpp
+ $(CXX) -g -c $(CXXFLAGS) -Wall -o main.o main.cpp
+
+node.o: node.cpp node.hpp
+ $(CXX) -g -c $(CXXFLAGS) -Wall -o node.o node.cpp
+
+codegen.o: codegen.cpp codegen.hpp
+ $(CXX) -g -c $(CXXFLAGS) -Wall -o codegen.o codegen.cpp
+
+lex.grammar.o: lex.grammar.c grammar.hpp
+ $(CXX) -g -c $(CXXFLAGS) -Wall -o lex.grammar.o lex.grammar.c
+
+grammar.o: grammar.cpp
+ $(CXX) -g -c $(CXXFLAGS) -Wall -o grammar.o grammar.cpp
+
+lex.grammar.c: grammar.l node.hpp
+ flex -o lex.grammar.c -Pgrammar grammar.l
+
+grammar.cpp: grammar.y node.hpp
+ bison -d -v --report-file=grammar.output -p grammar -d -o grammar.cpp grammar.y
+
+grammar.hpp: grammar.y node.hpp
+ bison -d -v --report-file=grammar.output -p grammar -d -o grammar.cpp grammar.y
+
+clean:
+ -rm grammar.cpp grammar.hpp
+ -rm lex.grammar.c
+ -rm -f *.o
+ -rm -f main
+
+test: main
+ ./main < test.c
+
diff --git a/old/toy/codegen.cpp b/old/toy/codegen.cpp
new file mode 100644
index 0000000..6841984
--- /dev/null
+++ b/old/toy/codegen.cpp
@@ -0,0 +1,239 @@
+#include "codegen.hpp"
+#include "node.hpp"
+#include "grammar.hpp"
+
+#include <vector>
+#include <typeinfo>
+
+#include <llvm/IR/Value.h>
+#include <llvm/IR/Type.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/PassManager.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/Assembly/PrintModulePass.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/JIT.h>
+#include <llvm/ExecutionEngine/Interpreter.h>
+
+using namespace std;
+using namespace llvm;
+
+CodeGenContext::CodeGenContext( )
+{
+ m_module = new Module( "main", getGlobalContext( ) );
+}
+
+void CodeGenContext::generateCode( NBlock& _root )
+{
+ /* Create the top level interpreter function to call as entry */
+ vector<Type*> argTypes;
+ FunctionType *ftype = FunctionType::get( Type::getVoidTy( getGlobalContext( ) ),
+ makeArrayRef( argTypes ), false );
+ m_mainFunction = Function::Create( ftype, GlobalValue::InternalLinkage, "main", m_module );
+ BasicBlock *bblock = BasicBlock::Create( getGlobalContext( ), "entry", m_mainFunction, 0 );
+
+ pushBlock( bblock );
+ _root.codeGen( *this );
+ ReturnInst::Create( getGlobalContext( ), bblock );
+ popBlock( );
+}
+
+void CodeGenContext::printGeneratedCode( )
+{
+ PassManager pm;
+ pm.add( createPrintModulePass( &outs( ) ) );
+ pm.run( *m_module );
+}
+
+std::string CodeGenContext::getGeneratedCode( )
+{
+ PassManager pm;
+ std::string s;
+ raw_string_ostream os( s );
+ pm.add( createPrintModulePass( &os ) );
+ pm.run( *m_module );
+ return s;
+}
+
+GenericValue CodeGenContext::runCode( )
+{
+ string error;
+ GenericValue returnValue;
+
+ ExecutionEngine *engine = EngineBuilder( m_module ).setErrorStr( &error ).create( );
+ if( !engine ) {
+ cerr << "ERROR: " << error << endl;
+ return returnValue;
+ }
+
+ vector<GenericValue> args;
+ returnValue = engine->runFunction( m_mainFunction, args );
+
+ return returnValue;
+}
+
+void CodeGenContext::pushBlock( BasicBlock *block )
+{
+ m_blocks.push( new CodeGenBlock( ) );
+ m_blocks.top( )->m_block = block;
+}
+
+void CodeGenContext::popBlock( )
+{
+ CodeGenBlock *top = m_blocks.top( );
+ m_blocks.pop( );
+ delete top;
+}
+
+BasicBlock *CodeGenContext::currentBlock( )
+{
+ return m_blocks.top( )->m_block;
+}
+
+llvm::Type *CodeGenContext::variableType( const NIdentifier& _type )
+{
+ if( _type.m_name.compare( "int" ) == 0 ) {
+ return Type::getInt32Ty( getGlobalContext( ) );
+ } else if( _type.m_name.compare( "double" ) == 0 ) {
+ return Type::getDoubleTy( getGlobalContext( ) );
+ } else if( _type.m_name.compare( "void" ) == 0 ) {
+ return Type::getVoidTy( getGlobalContext( ) );
+ } else {
+ cerr << "illegal type '" << _type << "'" << endl;
+ return 0;
+ }
+}
+
+// code generators per ADT node
+
+Value* Node::codeGen( CodeGenContext& context )
+{
+ cout << "Generating code for abstract node of type " << typeid( *this ).name( ) << endl;
+ return 0;
+}
+
+Value *NBlock::codeGen( CodeGenContext& context )
+{
+ Value *code = 0;
+ StatementList::const_iterator end = m_statements.end( );
+ cout << "Starting block" << endl;
+ for( StatementList::const_iterator it = m_statements.begin( );
+ it != end; it++ ) {
+ cout << "Generating code for " << typeid( *(*it) ).name( ) << endl;
+ code = (*(*it)).codeGen( context );
+ }
+ cout << "End of block" << endl;
+ return code;
+}
+
+Value *NAssignment::codeGen( CodeGenContext& context )
+{
+ cout << "Creating assignment for variable " << m_lhs.m_name << endl;
+ CodeGenContext::Locals::const_iterator var;
+ if( context.locals( ).find( m_lhs.m_name ) == context.locals( ).end( ) ) {
+ cerr << "Undeclared variable '" << m_lhs.m_name << "'" << endl;
+ return 0;
+ }
+ return new StoreInst( m_rhs.codeGen( context ),
+ context.locals( )[m_lhs.m_name], false,
+ context.currentBlock( ) );
+}
+
+Value *NVariableDeclaration::codeGen( CodeGenContext& context )
+{
+ cout << "Creating for a a variable declaration with name '"
+ << m_name.m_name << "' of type '" << m_type.m_name << "'" << endl;
+ AllocaInst *alloca = new AllocaInst( CodeGenContext::variableType( m_type ),
+ m_name.m_name.c_str( ), context.currentBlock( ) );
+ context.locals( )[m_name.m_name] = alloca;
+ if( m_assigned_expr ) {
+ NAssignment assignment( m_name, *m_assigned_expr );
+ assignment.codeGen( context );
+ }
+ return alloca;
+}
+
+Value *NInteger::codeGen( CodeGenContext& context )
+{
+ cout << "Creating code for integer constant '" << m_value << "'" << endl;
+ return ConstantInt::get( Type::getInt32Ty( getGlobalContext( ) ), m_value, true );
+}
+
+Value *NFunctionCall::codeGen( CodeGenContext& context )
+{
+ Function *function = context.module( )->getFunction( m_name.m_name.c_str( ) );
+ if( function == NULL ) {
+ cerr << "No such function '" << m_name.m_name << "'" << endl;
+ }
+
+ vector<Value *> args;
+ ExpressionList::const_iterator it, end = m_arguments.end( );
+ for( it = m_arguments.begin( ); it != end; it++ ) {
+ args.push_back( (**it).codeGen( context ) );
+ }
+ CallInst *call = CallInst::Create( function, makeArrayRef( args ), "", context.currentBlock( ) );
+ cout << "Created function invocation for '" << m_name.m_name << "'" << endl;
+
+ return call;
+}
+
+Value *NExpressionStatement::codeGen( CodeGenContext& context )
+{
+ cout << "Generating code for " << typeid( m_expression ).name( ) << endl;
+ return m_expression.codeGen( context );
+}
+
+Value *NFunctionDeclaration::codeGen( CodeGenContext& context )
+{
+ vector<Type *> argTypes;
+ VariableList::const_iterator it, end = m_arguments.end( );
+ for( it = m_arguments.begin( ); it != end; it++ ) {
+ argTypes.push_back( CodeGenContext::variableType( (**it).m_type ) );
+ }
+ FunctionType *ftype = FunctionType::get( CodeGenContext::variableType( m_type ),
+ makeArrayRef( argTypes ), false );
+ Function *function = Function::Create( ftype, GlobalValue::InternalLinkage,
+ m_name.m_name.c_str( ), context.module( ) );
+ BasicBlock *bblock = BasicBlock::Create( getGlobalContext( ), "entry", function, 0 );
+
+ context.pushBlock( bblock );
+
+ for( it = m_arguments.begin( ); it != end; it++ ) {
+ (**it).codeGen( context );
+ }
+
+ m_block.codeGen( context );
+ ReturnInst::Create( getGlobalContext( ), bblock );
+
+ context.popBlock( );
+
+ cout << "Created function '" << m_name.m_name << "'" << endl;
+
+ return function;
+}
+
+Value *NIdentifier::codeGen( CodeGenContext& context )
+{
+ cout << "Creating identifier reference to variable '" << m_name << "'" << endl;
+ if( context.locals( ).find( m_name ) == context.locals( ).end( ) ) {
+ cerr << "undeclared variable '" << m_name << "'" << endl;
+ return 0;
+ }
+ return new LoadInst( context.locals( )[m_name], "", false, context.currentBlock( ) );
+}
+
+Value *NBinaryOperator::codeGen( CodeGenContext& context )
+{
+ cout << "Creating binary operation '" << m_op << "'" << endl;
+
+ Instruction::BinaryOps instr;
+ switch( m_op ) {
+ case TPLUS: instr = Instruction::Add; break;
+ case TMUL: instr = Instruction::Mul; break;
+ default: cerr << "Illegal operation '" << m_op << "'" << endl; return 0;
+ }
+
+ return BinaryOperator::Create( instr, m_lhs.codeGen( context ),
+ m_rhs.codeGen( context ), "", context.currentBlock( ) );
+}
diff --git a/old/toy/codegen.hpp b/old/toy/codegen.hpp
new file mode 100644
index 0000000..6db068e
--- /dev/null
+++ b/old/toy/codegen.hpp
@@ -0,0 +1,53 @@
+#ifndef _CODEGEN_H_
+#define _CODEGEN_H_
+
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/IR/Value.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/ExecutionEngine/GenericValue.h>
+
+#include <map>
+#include <stack>
+#include <string>
+
+class Node;
+class NBlock;
+class NIdentifier;
+
+// this is one generated block of LLVM code, containing also
+// all local variables known in this scope
+class CodeGenBlock
+{
+ public:
+ llvm::BasicBlock *m_block;
+ std::map<std::string, llvm::Value *> m_locals;
+};
+
+// this class we pass along our ADT structure
+class CodeGenContext
+{
+ public:
+ typedef std::map<std::string, llvm::Value *> Locals;
+ private:
+ std::stack<CodeGenBlock *> m_blocks;
+ llvm::Module *m_module;
+ llvm::Function *m_mainFunction;
+ Locals m_locals;
+
+ public:
+ CodeGenContext( );
+ void printGeneratedCode( );
+ std::string getGeneratedCode( );
+ void generateCode( NBlock& _root );
+ llvm::GenericValue runCode( );
+ static llvm::Type *variableType( const NIdentifier& _type );
+ void pushBlock( llvm::BasicBlock *_block );
+ void popBlock( );
+ llvm::BasicBlock *currentBlock( );
+ Locals& locals( ) { return m_blocks.top( )->m_locals; }
+ llvm::Module *module( ) { return m_module; }
+
+};
+
+#endif // _CODEGEN_H_
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org).htm b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org).htm
new file mode 100644
index 0000000..2c897a9
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org).htm
@@ -0,0 +1,1044 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <title> Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)</title>
+ <meta equiv="X-UA-Compatible" content="chrome=1">
+ <meta name="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="Keywords" content="loren segal, blog, blogging, youtube, videos, web, programming, ruby, python, languages, software, computing, computers, nerd, web, internet, bison, compiler, flex, grammar, guide, how to, llvm, programming languages, ">
+ <meta name="Description" content="I'm Loren Segal, a programmer, Rubyist, author of YARD, musician, photographer and writer from Montreal, Canada. This is my blog.">
+ <meta name="blogcatalog" content="9BC8940314">
+ <meta name="Author" content="Loren Segal">
+ <link rel="address bar icon" href="http://gnuu.org/favicon.ico">
+ <link rel="pingback" href="http://gnuu.org/xmlrpc.php">
+ <link rel="alternate" type="application/rss+xml" href="http://feeds.feedburner.com/connectnothing">
+ <script type="text/javascript" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/jquery.js"></script>
+ <script type="text/javascript" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/twitter.js"></script>
+ <script type="text/javascript" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/highlight.js"></script>
+ <script type="text/javascript">
+ $(function() {
+ $('#content pre').each(function() {
+ if ($(this).parents('.gist').size() > 0) return;
+ var code = $(this).children('code');
+ if (code.length == 0) {
+ $(this).html('<code class="' + this.className.replace(/^sh_/, '') + '">' + $(this).html() + '</code>');
+ }
+ });
+ hljs.initHighlighting();
+ });
+
+ </script>
+ <link rel="stylesheet" href="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/style.css" type="text/css" media="screen">
+ <link rel="archives" title="June 2013" href="http://gnuu.org/2013/06/">
+ <link rel="archives" title="January 2013" href="http://gnuu.org/2013/01/">
+ <link rel="archives" title="April 2012" href="http://gnuu.org/2012/04/">
+ <link rel="archives" title="February 2012" href="http://gnuu.org/2012/02/">
+ <link rel="archives" title="October 2011" href="http://gnuu.org/2011/10/">
+ <link rel="archives" title="July 2011" href="http://gnuu.org/2011/07/">
+ <link rel="archives" title="June 2011" href="http://gnuu.org/2011/06/">
+ <link rel="archives" title="May 2011" href="http://gnuu.org/2011/05/">
+ <link rel="archives" title="April 2011" href="http://gnuu.org/2011/04/">
+ <link rel="archives" title="January 2011" href="http://gnuu.org/2011/01/">
+ <link rel="archives" title="December 2010" href="http://gnuu.org/2010/12/">
+ <link rel="archives" title="October 2010" href="http://gnuu.org/2010/10/">
+ <link rel="archives" title="September 2010" href="http://gnuu.org/2010/09/">
+ <link rel="archives" title="August 2010" href="http://gnuu.org/2010/08/">
+ <link rel="archives" title="June 2010" href="http://gnuu.org/2010/06/">
+ <link rel="archives" title="May 2010" href="http://gnuu.org/2010/05/">
+ <link rel="archives" title="April 2010" href="http://gnuu.org/2010/04/">
+ <link rel="archives" title="March 2010" href="http://gnuu.org/2010/03/">
+ <link rel="archives" title="December 2009" href="http://gnuu.org/2009/12/">
+ <link rel="archives" title="November 2009" href="http://gnuu.org/2009/11/">
+ <link rel="archives" title="October 2009" href="http://gnuu.org/2009/10/">
+ <link rel="archives" title="September 2009" href="http://gnuu.org/2009/09/">
+ <link rel="archives" title="August 2009" href="http://gnuu.org/2009/08/">
+ <link rel="archives" title="July 2009" href="http://gnuu.org/2009/07/">
+ <link rel="archives" title="June 2009" href="http://gnuu.org/2009/06/">
+ <link rel="archives" title="May 2009" href="http://gnuu.org/2009/05/">
+ <link rel="archives" title="March 2009" href="http://gnuu.org/2009/03/">
+ <link rel="archives" title="February 2009" href="http://gnuu.org/2009/02/">
+ <link rel="archives" title="January 2009" href="http://gnuu.org/2009/01/">
+ <link rel="archives" title="October 2008" href="http://gnuu.org/2008/10/">
+ <link rel="archives" title="September 2008" href="http://gnuu.org/2008/09/">
+ <link rel="archives" title="August 2008" href="http://gnuu.org/2008/08/">
+ <link rel="archives" title="July 2008" href="http://gnuu.org/2008/07/">
+ <link rel="archives" title="May 2008" href="http://gnuu.org/2008/05/">
+ <link rel="archives" title="April 2008" href="http://gnuu.org/2008/04/">
+ <link rel="archives" title="March 2008" href="http://gnuu.org/2008/03/">
+ <link rel="archives" title="February 2008" href="http://gnuu.org/2008/02/">
+ <link rel="archives" title="January 2008" href="http://gnuu.org/2008/01/">
+ <link rel="alternate" type="application/rss+xml" title="gnuu.org » Writing Your Own Toy Compiler Using Flex, Bison and LLVM Comments Feed" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/feed/">
+<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://gnuu.org/xmlrpc.php?rsd">
+<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://gnuu.org/wp-includes/wlwmanifest.xml">
+<link rel="prev" title="The Angel" href="http://gnuu.org/2009/09/17/the-angel/">
+<link rel="next" title="The Joy of Solving Problems, All of Them" href="http://gnuu.org/2009/10/01/the-joy-of-solving-problems-all-of-them/">
+<meta name="generator" content="WordPress 3.5">
+<link rel="canonical" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/">
+<link rel="shortlink" href="http://wp.me/pkEpr-4i">
+ <script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_002.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_003.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_008.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_005.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_006.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_007.php" async="" type="text/javascript"></script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/in_004.php" async="" type="text/javascript"></script></head>
+ <body>
+ <div id="wrapper">
+ <div id="content">
+ <a id="title" href="http://gnuu.org/"></a>
+
+
+ <div class="post" id="post-266">
+ <h1 class="storytitle">Writing Your Own Toy Compiler Using Flex, Bison and LLVM</h1>
+ <div class="meta">
+ <p>By Loren Segal on September 18th, 2009 at 1:08 PM </p>
+ </div>
+
+ <div class="storycontent">
+ <p style="text-align:left"></p><form name="content_jump"><select class="contentjumpddl" onchange="location = this.options[this.selectedIndex].value;"><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/">1. Introduction</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/2/">2. Getting Started</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/3/">3. Step1. Lexical Analysis with Flex</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/4/">4. Step 2. Semantic Parsing with Bison</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/5/">5. Generating Flex and Bison Code</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/6/">6. Step 3. Assembling the AST with LLVM</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/7/">7. Building and Running Our Toy Language</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/8/">8. Conclusion</option><option value="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/all/1" selected="selected">9. View All</option></select></form><p></p><p><!--pagetitle:Introduction--></p>
+<p class="note"><strong>Update (March 19 2010)</strong>: this article was updated for <strong>LLVM 2.6</strong> thanks to a great patch by <a href="http://github.com/ashgti/my_toy_compiler">John Harrison</a>. He rocks!</p>
+<p>I’ve always been interested in compilers and languages, but interest
+only gets you so far. A lot of the concepts of compiler design can
+easily go way over most programmers’ heads, even the intelligent ones.
+Needless to say, I’ve tried, without much success, to write a small toy
+language/compiler before. I’d usually get caught up at the semantic
+parsing stage. And again, needless to say, this post is mostly inspired
+by my latest attempt, though this one has been much more successful (so
+far).</p>
+<p>Fortunately over the last few years I’ve been involved in <a href="http://yard.soen.ca/">some</a> <a href="http://www.eecs.ucf.edu/%7Eleavens/JML//index.shtml">projects</a>
+ that helped give me perspective and experience on what’s really
+involved in building a compiler. The other thing I’ve been lucky to have
+ in my corner this time is the help of <a href="http://llvm.org/">LLVM</a>,
+ a tool which I’m hardly qualified to talk too much about, but it’s been
+ quite handy in implementing most of the business end (read: complex
+aspects) of my toy compiler.</p>
+<p> <!-- more --><br>
+</p><h2>So Why Are You Reading This? </h2>
+<p>Maybe you want to see what I’ve been doing with my time. It’s more
+likely, however, that you’re probably interested in compilers and
+languages as I am, and have probably been hitting similar roadblocks.
+You’ve probably wanted to try this but never found the resources, or did
+ but couldn’t quite follow. The goal of this article is to provide such a
+ resource and explain in a relatively step by step manner how to create
+the most basic-but-functional compiler from start to “finishâ€. </p>
+<p>I won’t be covering much theory, so if you haven’t brushed up on your <a href="http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form">BNF grammars</a>, <a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">AST data structures</a> and the basic <a href="http://en.wikipedia.org/wiki/Compiler">compiler pipeline</a>,
+ I suggest you do so. That said, I plan on keeping this as simple as
+possible. The goal, of course, is to make this an easy-to-understand
+introductory resource for people interested but not experienced with
+compilers. </p>
+<h2></h2>
+<h2>What You Will End Up With</h2>
+<p>If you follow this article, you should end up with a language that
+can define functions, call functions, define variables, assign data to
+variables and perform basic math operations. It will support two basic
+types, doubles and integers. Some of the functionality is unimplemented,
+ so you can have the satisfaction of actually implementing some of this
+stuff yourself and get the hang of writing a compiler with a little
+help.</p>
+<h2>Let’s Get Some Questions Out of the Way</h2>
+<h3>1. What languages do I need to know?</h3>
+<p>The tools we’ll be using are C/C++ based. LLVM is specifically C++
+and our toy language will follow suit since there are some niceties of
+OOP and the STL (C++’s stdlib) that make for fewer lines of code. In
+addition to C, both Lex and Bison have their own syntax which may seem
+daunting at first, but I’ll try to explain as much as possible. The
+grammar we’re dealing with is actually very tiny (~100 LOC), so it
+should be feasible.</p>
+<h3>2. Is this really complicated? </h3>
+<p>Yes and no. There is plenty of stuff going on here and it might seem
+scary at first, but honestly, this is about as simple as it gets. We
+will also use a lot of tools to abstract the layers of complexity and
+make it manageable.</p>
+<h3>3. How long will it take?</h3>
+<p>What we will be building took me about 3 days of toying with, but I
+have a few failed attempts under my belt and those do have impact on my
+comprehension. Of course, this will be a “follow me†kind of deal, so it
+ should be much shorter for you. To understand completely everything
+might take a little longer, but you should be able to run through all of
+ this stuff (and hopefully understand a good amount of it) in an
+afternoon.</p>
+<p>So, if you’re ready, let’s get started.</p>
+<p><!--nextpage--><br>
+<!--pagetitle:Getting Started--></p>
+<h2>The Basic Compiler Recipe</h2>
+<p>Although you should already pretty much know this, a compiler is
+really a grouping of three to four components (there are some more
+sub-components) where data is fed from one to the next in a pipeline
+fashion. We will be using a different tool to help us build out each of
+these components. Here is a diagram of each step and the tool we will
+use:</p>
+<p><img alt="Compiler Pipeline" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/pipeline.png" height="76" width="620"> </p>
+<p>You’ll notice the linker step is greyed out. Our toy language won’t
+be supporting compile time linking (plus most languages don’t do compile
+ time linking anymore anyway). To do our lexing we will be using the
+open source tool Lex, mostly available these days as <a href="http://flex.sourceforge.net/">Flex</a>. Lexing usually goes hand in hand with semantic parsing, which we’ll be performing with the help of Yacc, better known as <a href="http://www.gnu.org/software/bison/">Bison</a>.
+ Finally, once semantic parsing is done we can walk over our AST and
+generate our “bytecodeâ€, or machine code. For this, we’ll be using <a href="http://llvm.org/">LLVM</a>,
+ which technically generates intermediate bytecode, but we will be using
+ LLVM’s JIT (Just In Time) compilation to execute this bytecode on our
+machine. </p>
+<p>To summarize, the steps are as follows:</p>
+<ol>
+<li><strong>Lexical Analysis with <em>Flex</em></strong>: Split input data into a set of tokens (identifiers, keywords, numbers, brackets, braces, etc.) </li>
+<li><strong>Semantic Parsing with <em>Bison</em></strong>: Generate an AST while parsing the tokens. Bison will do most of the legwork here, we just need to define our AST. </li>
+<li><strong>Assembly with <em>LLVM</em></strong>: This is where we walk over our AST and generate byte/machine code for each node. As crazy as it sounds, this is probably the <em>easiest</em> step. </li>
+</ol>
+<p>Before moving too far along, you should probably consider installing
+Flex, Bison and LLVM, if you haven’t already. We’re going to need them
+pretty soon.</p>
+<h2></h2>
+<h2>Defining Our Grammar</h2>
+<p>Our grammar is naturally the most central part of our language. From
+our grammar we inherently allow or disallow functionality. For our toy
+compiler, we will be using a standard C-like syntax because it’s
+familiar and simple to parse. The canonical example of our toy language
+will be the following code:</p>
+<pre><code class="c ruby"><span class="identifier">int</span> <span class="identifier">do_math</span>(<span class="identifier">int</span> <span class="identifier">a</span>) {
+ <span class="identifier">int</span> <span class="identifier">x</span> = <span class="identifier">a</span> * <span class="number">5</span> + <span class="number">3</span>
+}
+
+<span class="identifier">do_math</span>(<span class="number">10</span>)</code></pre>
+<p>Looks simple enough. We can see it’s typed the same way C is, but
+there are no semicolons separating statements. You’ll also notice there
+is no “return†statement in our grammar; this is something you can
+implement on your own.</p>
+<p>There’s also no mechanism to print any results or anything. We will verify the correctness of our programs by inspecting the <em>very pretty</em> instruction listing that LLVM can print of the bytecode we’ve compiled, but more on that later.</p>
+<p><!--nextpage--><br>
+<!--pagetitle:Step1. Lexical Analysis with Flex--></p>
+<h2>Step 1. Lexical Analysis with Flex</h2>
+<p>This is the simplest step. Given our grammar, we need to break down
+our input into a list of known tokens. As mentioned before, our grammar
+has very basic tokens: identifiers, numbers (integers and floats), the
+mathematical operators, parentheses and braces. Our lex file “tokens.lâ€,
+ which has a somewhat specialized grammar, is simply defined as:</p>
+<p class="note">Listing of tokens.l:</p>
+<pre><code class="cpp">%{
+<span class="preprocessor">#include &lt;string&gt;</span>
+<span class="preprocessor">#include "node.h"</span>
+<span class="preprocessor">#include "parser.hpp"</span>
+<span class="preprocessor">#define SAVE_TOKEN yylval.string = new std::string(yytext, yyleng)</span>
+<span class="preprocessor">#define TOKEN(t) (yylval.token = t)</span>
+<span class="keyword">extern</span> <span class="string">"C"</span> <span class="keyword">int</span> yywrap() { }
+%}
+
+%%
+
+[ \t\n] ;
+[a-zA-Z_][a-zA-Z0-<span class="number">9</span>_]* SAVE_TOKEN; <span class="keyword">return</span> TIDENTIFIER;
+[<span class="number">0</span>-<span class="number">9</span>]+\.[<span class="number">0</span>-<span class="number">9</span>]* SAVE_TOKEN; <span class="keyword">return</span> TDOUBLE;
+[<span class="number">0</span>-<span class="number">9</span>]+ SAVE_TOKEN; <span class="keyword">return</span> TINTEGER;
+<span class="string">"="</span> <span class="keyword">return</span> TOKEN(TEQUAL);
+<span class="string">"=="</span> <span class="keyword">return</span> TOKEN(TCEQ);
+<span class="string">"!="</span> <span class="keyword">return</span> TOKEN(TCNE);
+<span class="string">"&lt;"</span> <span class="keyword">return</span> TOKEN(TCLT);
+<span class="string">"&lt;="</span> <span class="keyword">return</span> TOKEN(TCLE);
+<span class="string">"&gt;"</span> <span class="keyword">return</span> TOKEN(TCGT);
+<span class="string">"&gt;="</span> <span class="keyword">return</span> TOKEN(TCGE);
+<span class="string">"("</span> <span class="keyword">return</span> TOKEN(TLPAREN);
+<span class="string">")"</span> <span class="keyword">return</span> TOKEN(TRPAREN);
+<span class="string">"{"</span> <span class="keyword">return</span> TOKEN(TLBRACE);
+<span class="string">"}"</span> <span class="keyword">return</span> TOKEN(TRBRACE);
+<span class="string">"."</span> <span class="keyword">return</span> TOKEN(TDOT);
+<span class="string">","</span> <span class="keyword">return</span> TOKEN(TCOMMA);
+<span class="string">"+"</span> <span class="keyword">return</span> TOKEN(TPLUS);
+<span class="string">"-"</span> <span class="keyword">return</span> TOKEN(TMINUS);
+<span class="string">"*"</span> <span class="keyword">return</span> TOKEN(TMUL);
+<span class="string">"/"</span> <span class="keyword">return</span> TOKEN(TDIV);
+. printf(<span class="string">"Unknown token!\n"</span>); yyterminate();
+
+%%</code></pre>
+<p>The first section declares some specialized C code. We use a
+“SAVE_TOKEN†macro to keep the text of identifiers and numbers somewhere
+ safe (instead of just the token itself), since Bison won’t have access
+to our ‘yytext’ variable. The first token tells us to skip all
+whitespace. You’ll also notice that we have some equality comparison
+tokens and such. Those are unimplemented for now, feel free to support
+them in your toy compiler!</p>
+<p>So all we’re doing here is defining the tokens and their symbolic
+names. These symbols (TIDENTIFIER, etc.) will become “terminal symbolsâ€
+in our grammar. We’re just returning them, but we’ve never defined them.
+ <strong>Where are they defined?</strong> Why, in the bison grammar, of
+course. The parser.hpp file we’ve included will be generated by bison,
+and all the tokens inside it will be generated and available for use.</p>
+<p>We run Flex on this tokens.l file to generate our “tokens.cpp†file,
+which will be compiled alongside our parser and provide the yylex()
+function that recognizes all of these tokens. We will run this command
+later though, because we need to generate that header file from bison
+first!</p>
+<p><!--nextpage--><br>
+<!--pagetitle:Step 2. Semantic Parsing with Bison--></p>
+<h2>Step 2. Semantic Parsing with Bison</h2>
+<p>This is the challenging part of our mission. Generating an accurate,
+unambiguous grammar is not simple and takes a little bit of practice.
+Fortunately, our grammar is both simple and, for your benefit, mostly
+completed. Before we get into implementing our grammar, though, we need
+to talk design for a bit.</p>
+<h3>Designing the AST</h3>
+<p>The end product of semantic parsing is an AST. As we will see, Bison
+is quite elegantly optimized to generate AST’s; it’s really only a
+matter of plugging our nodes into the grammar. </p>
+<p>The same way a string such as “int x†represents our language in text
+ form, our AST is what represents our language in memory (before it is
+assembled). As such, we need to build up the data structures we will be
+using before we have the chance of plugging them into our grammar file.
+This process is pretty straightforward because we are basically creating
+ a structure for every semantic that can be expressed by our language.
+Method calls, method declarations, variable declarations, references,
+these are all candidates for AST nodes. A complete diagram of the nodes
+in our language is as follows:</p>
+<p><img alt="Our Toy Language AST" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/ClassDiagram.png" border="0" height="505" width="640"> </p>
+<p>The C++ that represents the above specifications is:</p>
+<p class="note">Listing of node.h:</p>
+<pre><code class="cpp"><span class="preprocessor">#include &lt;iostream&gt;</span>
+<span class="preprocessor">#include &lt;vector&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Value.h&gt;</span>
+
+<span class="keyword">class</span> CodeGenContext;
+<span class="keyword">class</span> NStatement;
+<span class="keyword">class</span> NExpression;
+<span class="keyword">class</span> NVariableDeclaration;
+
+<span class="keyword">typedef</span> <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;NStatement*&gt;</span> StatementList;
+<span class="keyword">typedef</span> <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;NExpression*&gt;</span> ExpressionList;
+<span class="keyword">typedef</span> <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;NVariableDeclaration*&gt;</span> VariableList;
+
+<span class="keyword">class</span> Node {
+<span class="keyword">public</span>:
+ <span class="keyword">virtual</span> ~Node() {}
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context) { }
+};
+
+<span class="keyword">class</span> NExpression : <span class="keyword">public</span> Node {
+};
+
+<span class="keyword">class</span> NStatement : <span class="keyword">public</span> Node {
+};
+
+<span class="keyword">class</span> NInteger : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ <span class="keyword">long</span> <span class="keyword">long</span> value;
+ NInteger(<span class="keyword">long</span> <span class="keyword">long</span> value) : value(value) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NDouble : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ <span class="keyword">double</span> value;
+ NDouble(<span class="keyword">double</span> value) : value(value) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NIdentifier : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ <span class="built_in">std</span>::<span class="built_in">string</span> name;
+ NIdentifier(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; name) : name(name) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NMethodCall : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ <span class="keyword">const</span> NIdentifier&amp; id;
+ ExpressionList arguments;
+ NMethodCall(<span class="keyword">const</span> NIdentifier&amp; id, ExpressionList&amp; arguments) :
+ id(id), arguments(arguments) { }
+ NMethodCall(<span class="keyword">const</span> NIdentifier&amp; id) : id(id) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NBinaryOperator : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ <span class="keyword">int</span> op;
+ NExpression&amp; lhs;
+ NExpression&amp; rhs;
+ NBinaryOperator(NExpression&amp; lhs, <span class="keyword">int</span> op, NExpression&amp; rhs) :
+ lhs(lhs), rhs(rhs), op(op) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NAssignment : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ NIdentifier&amp; lhs;
+ NExpression&amp; rhs;
+ NAssignment(NIdentifier&amp; lhs, NExpression&amp; rhs) :
+ lhs(lhs), rhs(rhs) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NBlock : <span class="keyword">public</span> NExpression {
+<span class="keyword">public</span>:
+ StatementList statements;
+ NBlock() { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NExpressionStatement : <span class="keyword">public</span> NStatement {
+<span class="keyword">public</span>:
+ NExpression&amp; expression;
+ NExpressionStatement(NExpression&amp; expression) :
+ expression(expression) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NVariableDeclaration : <span class="keyword">public</span> NStatement {
+<span class="keyword">public</span>:
+ <span class="keyword">const</span> NIdentifier&amp; type;
+ NIdentifier&amp; id;
+ NExpression *assignmentExpr;
+ NVariableDeclaration(<span class="keyword">const</span> NIdentifier&amp; type, NIdentifier&amp; id) :
+ type(type), id(id) { }
+ NVariableDeclaration(<span class="keyword">const</span> NIdentifier&amp; type, NIdentifier&amp; id, NExpression *assignmentExpr) :
+ type(type), id(id), assignmentExpr(assignmentExpr) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};
+
+<span class="keyword">class</span> NFunctionDeclaration : <span class="keyword">public</span> NStatement {
+<span class="keyword">public</span>:
+ <span class="keyword">const</span> NIdentifier&amp; type;
+ <span class="keyword">const</span> NIdentifier&amp; id;
+ VariableList arguments;
+ NBlock&amp; block;
+ NFunctionDeclaration(<span class="keyword">const</span> NIdentifier&amp; type, <span class="keyword">const</span> NIdentifier&amp; id,
+ <span class="keyword">const</span> VariableList&amp; arguments, NBlock&amp; block) :
+ type(type), id(id), arguments(arguments), block(block) { }
+ <span class="keyword">virtual</span> llvm::Value* codeGen(CodeGenContext&amp; context);
+};</code></pre>
+<p>Again, fairly straightforward. We’re not using any getters or setters
+ here, just public data members; there’s really no need for data hiding.
+ Ignore the codeGen method for now. It will come in handy later, when we
+ want to export our AST as LLVM bytecode.</p>
+<h3>Back to Bison</h3>
+<p>Moo. I mean, whatever Bison say. Here’s a short tangent:</p>
+<table cellpadding="2" cellspacing="0" border="0" width="400">
+<tbody>
+<tr>
+<td valign="top" width="200"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Bison1" alt="Bison1" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/image.png" border="0" height="113" width="300"></td>
+<td valign="top" width="200"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Bison2" alt="Bison2" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/image1.png" border="0" height="140" width="280"></td>
+</tr>
+</tbody>
+</table>
+<p>Anyway, here comes the most complex part and by the same token, the
+hardest to explain. It’s not technically complicated, but I’d have to
+spend a while discussing the details of Bison’s syntax, so let’s take a
+lot of it for granted right now. Realize this, though: we’ll be
+declaring the makeup of each of our valid statements and expressions
+(the ones representing the nodes we’ve defined above) using terminal and
+ non-terminal symbols, basically like a BNF grammar. The syntax is also
+similar:</p>
+<pre><code class=" ruby"><span class="identifier">if_stmt</span> <span class="symbol">:</span> <span class="constant">IF</span> <span class="string">'('</span> <span class="identifier">condition</span> <span class="string">')'</span> <span class="identifier">block</span> { <span class="regexp">/* do stuff when this rule is encountered */</span> }
+ | <span class="constant">IF</span> <span class="string">'('</span> <span class="identifier">condition</span> <span class="string">')'</span> { ... }
+ ;</code></pre>
+<p>The above would define an if statement (<em>if</em> we supported it).
+ The real difference is that with each grammar comes a set of actions
+(inside the braces) which are executed after it is recognized. This is
+done recursively over the symbols in leaf-to-root order, where each non
+terminal is eventually merged into one big tree. The “$$†symbol you
+will be seeing represents the current root node of each leaf.
+Furthermore, “$1†represents the leaf for the 1st symbol in the rule. In
+ the above example, the “$$†we assigned from our “condition†rule would
+ be available as “$3" in our “if_stmt†rule. It might start becoming
+clear how our AST ties into this. We will basically be assigning a node
+to “$$†at each of our rules which will eventually be merged into our
+final AST. If not, don’t worry. The Bison part of our toy language is
+again, the most complex portion of our language. It might take a while
+to sink in. Besides, you haven’t even seen the code yet, so, here it is:</p>
+<p class="note">Listing of parser.y:</p>
+<pre><code class="cpp">%{
+ <span class="preprocessor">#include "node.h"</span>
+ NBlock *programBlock; <span class="comment">/* the top level root node of our final AST */</span>
+
+ <span class="keyword">extern</span> <span class="keyword">int</span> yylex();
+ <span class="keyword">void</span> yyerror(<span class="keyword">const</span> <span class="keyword">char</span> *s) { printf(<span class="string">"ERROR: %s\n"</span>, s); }
+%}
+
+<span class="comment">/* Represents the many different ways we can access our data */</span>
+%<span class="keyword">union</span> {
+ Node *node;
+ NBlock *block;
+ NExpression *expr;
+ NStatement *stmt;
+ NIdentifier *ident;
+ NVariableDeclaration *var_decl;
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;NVariableDeclaration*&gt;</span> *varvec;
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;NExpression*&gt;</span> *exprvec;
+ <span class="built_in">std</span>::<span class="built_in">string</span> *<span class="built_in">string</span>;
+ <span class="keyword">int</span> token;
+}
+
+<span class="comment">/* Define our terminal symbols (tokens). This should
+ match our tokens.l lex file. We also define the node type
+ they represent.
+ */</span>
+%token &lt;<span class="built_in">string</span>&gt; TIDENTIFIER TINTEGER TDOUBLE
+%token &lt;token&gt; TCEQ TCNE TCLT TCLE TCGT TCGE TEQUAL
+%token &lt;token&gt; TLPAREN TRPAREN TLBRACE TRBRACE TCOMMA TDOT
+%token &lt;token&gt; TPLUS TMINUS TMUL TDIV
+
+<span class="comment">/* Define the type of node our nonterminal symbols represent.
+ The types refer to the %union declaration above. Ex: when
+ we call an ident (defined by union type ident) we are really
+ calling an (NIdentifier*). It makes the compiler happy.
+ */</span>
+%type &lt;ident&gt; ident
+%type &lt;expr&gt; numeric expr
+%type &lt;varvec&gt; func_decl_args
+%type &lt;exprvec&gt; call_args
+%type &lt;block&gt; program stmts block
+%type &lt;stmt&gt; stmt var_decl func_decl
+%type &lt;token&gt; comparison
+
+<span class="comment">/* Operator precedence for mathematical operators */</span>
+%left TPLUS TMINUS
+%left TMUL TDIV
+
+%start program
+
+%%
+
+program : stmts { programBlock = $<span class="number">1</span>; }
+ ;
+
+stmts : stmt { $$ = <span class="keyword">new</span> NBlock(); $$-&gt;statements.push_back($&lt;stmt&gt;<span class="number">1</span>); }
+ | stmts stmt { $<span class="number">1</span>-&gt;statements.push_back($&lt;stmt&gt;<span class="number">2</span>); }
+ ;
+
+stmt : var_decl | func_decl
+ | expr { $$ = <span class="keyword">new</span> NExpressionStatement(*$<span class="number">1</span>); }
+ ;
+
+block : TLBRACE stmts TRBRACE { $$ = $<span class="number">2</span>; }
+ | TLBRACE TRBRACE { $$ = <span class="keyword">new</span> NBlock(); }
+ ;
+
+var_decl : ident ident { $$ = <span class="keyword">new</span> NVariableDeclaration(*$<span class="number">1</span>, *$<span class="number">2</span>); }
+ | ident ident TEQUAL expr { $$ = <span class="keyword">new</span> NVariableDeclaration(*$<span class="number">1</span>, *$<span class="number">2</span>, $<span class="number">4</span>); }
+ ;
+
+func_decl : ident ident TLPAREN func_decl_args TRPAREN block
+ { $$ = <span class="keyword">new</span> NFunctionDeclaration(*$<span class="number">1</span>, *$<span class="number">2</span>, *$<span class="number">4</span>, *$<span class="number">6</span>); <span class="keyword">delete</span> $<span class="number">4</span>; }
+ ;
+
+func_decl_args : <span class="comment">/*blank*/</span> { $$ = <span class="keyword">new</span> VariableList(); }
+ | var_decl { $$ = <span class="keyword">new</span> VariableList(); $$-&gt;push_back($&lt;var_decl&gt;<span class="number">1</span>); }
+ | func_decl_args TCOMMA var_decl { $<span class="number">1</span>-&gt;push_back($&lt;var_decl&gt;<span class="number">3</span>); }
+ ;
+
+ident : TIDENTIFIER { $$ = <span class="keyword">new</span> NIdentifier(*$<span class="number">1</span>); <span class="keyword">delete</span> $<span class="number">1</span>; }
+ ;
+
+numeric : TINTEGER { $$ = <span class="keyword">new</span> NInteger(atol($<span class="number">1</span>-&gt;c_str())); <span class="keyword">delete</span> $<span class="number">1</span>; }
+ | TDOUBLE { $$ = <span class="keyword">new</span> NDouble(atof($<span class="number">1</span>-&gt;c_str())); <span class="keyword">delete</span> $<span class="number">1</span>; }
+ ;
+
+expr : ident TEQUAL expr { $$ = <span class="keyword">new</span> NAssignment(*$&lt;ident&gt;<span class="number">1</span>, *$<span class="number">3</span>); }
+ | ident TLPAREN call_args TRPAREN { $$ = <span class="keyword">new</span> NMethodCall(*$<span class="number">1</span>, *$<span class="number">3</span>); <span class="keyword">delete</span> $<span class="number">3</span>; }
+ | ident { $&lt;ident&gt;$ = $<span class="number">1</span>; }
+ | numeric
+ | expr comparison expr { $$ = <span class="keyword">new</span> NBinaryOperator(*$<span class="number">1</span>, $<span class="number">2</span>, *$<span class="number">3</span>); }
+ | TLPAREN expr TRPAREN { $$ = $<span class="number">2</span>; }
+ ;
+
+call_args : <span class="comment">/*blank*/</span> { $$ = <span class="keyword">new</span> ExpressionList(); }
+ | expr { $$ = <span class="keyword">new</span> ExpressionList(); $$-&gt;push_back($<span class="number">1</span>); }
+ | call_args TCOMMA expr { $<span class="number">1</span>-&gt;push_back($<span class="number">3</span>); }
+ ;
+
+comparison : TCEQ | TCNE | TCLT | TCLE | TCGT | TCGE
+ | TPLUS | TMINUS | TMUL | TDIV
+ ;
+
+%%</code></pre>
+<p><!--nextpage--><br>
+<!--pagetitle:Generating Flex and Bison Code--></p>
+<h3>Generating Our Code</h3>
+<p>So we have our “tokens.l†file for Flex and our “parser.y†file for
+Bison. To generate our C++ source files from these definition files we
+need to pass them through the tools. Note that Bison will also be
+creating a “parser.hpp†header file for Flex; it does this because of
+the <code>–d</code> switch, which separates our token declarations from
+the source so we can include and use those tokens elsewhere. The
+following commands should create our parser.cpp, parser.hpp and
+tokens.cpp source files.</p>
+<pre><code class=" ruby"><span class="variable">$ </span><span class="identifier">bison</span> -<span class="identifier">d</span> -<span class="identifier">o</span> <span class="identifier">parser</span>.<span class="identifier">cpp</span> <span class="identifier">parser</span>.<span class="identifier">y</span>
+<span class="variable">$ </span><span class="identifier">lex</span> -<span class="identifier">o</span> <span class="identifier">tokens</span>.<span class="identifier">cpp</span> <span class="identifier">tokens</span>.<span class="identifier">l</span></code></pre>
+<p>If everything went well we should now have 2 out of 3 parts of our
+compiler. If you want to test this, create a short main function in a
+main.cpp file:</p>
+<p class="note">Listing of main.cpp:</p>
+<pre><code class="c ruby"><span class="comment">#include &lt;iostream&gt;</span>
+<span class="comment">#include "node.h"</span>
+<span class="identifier">extern</span> <span class="constant">NBlock</span>* <span class="identifier">programBlock</span>;
+<span class="identifier">extern</span> <span class="identifier">int</span> <span class="identifier">yyparse</span>();
+
+<span class="identifier">int</span> <span class="identifier">main</span>(<span class="identifier">int</span> <span class="identifier">argc</span>, <span class="identifier">char</span> **<span class="identifier">argv</span>)
+{
+ <span class="identifier">yyparse</span>();
+ <span class="identifier">std</span><span class="symbol">:</span><span class="symbol">:<span class="identifier">cout</span></span> &lt;&lt; <span class="identifier">programBlock</span> &lt;&lt; <span class="identifier">std</span><span class="symbol">:</span><span class="symbol">:<span class="identifier">endl</span></span>;
+ <span class="identifier"><span class="keyword">return</span></span> <span class="number">0</span>;
+}</code></pre>
+<p>You can then compile your source files:</p>
+<pre><code class=" ruby"><span class="variable">$ </span><span class="identifier">g</span>++ -<span class="identifier">o</span> <span class="identifier">parser</span> <span class="identifier">parser</span>.<span class="identifier">cpp</span> <span class="identifier">tokens</span>.<span class="identifier">cpp</span> <span class="identifier">main</span>.<span class="identifier">cpp</span></code></pre>
+<p class="note">You will need to have installed LLVM by now for the <code>llvm::Value</code>
+ reference in "node.h". If you don’t want to go that far just yet, you
+can comment out the codeGen() methods in node.h to test just your
+lexer/parser combo.</p>
+<p>If all goes well you should now have a “parser†binary that takes
+source in stdin and prints out a hopefully nonzero address representing
+the root node of our AST in memory. </p>
+<p><!--nextpage--><br>
+<!--pagetitle:Step 3. Assembling the AST with LLVM--></p>
+<h2>Step 3. Assembling the AST with LLVM</h2>
+<p>The next step in a compiler is to naturally take this AST and turn it
+ into machine code. This means converting each semantic node into the
+equivalent machine instruction. LLVM makes this very easy for us,
+because it abstracts the actual instructions to something that is
+similar to an AST. This means all we’re really doing is translating from
+ one AST to another.</p>
+<p>You can imagine that this process will involve us walking over our
+AST from our root node, and for each node we emit bytecode. This is
+where the <code>codeGen</code> method that we defined for our nodes comes in handy. For example, when we visit an <code>NBlock</code> node (semantically representing a collection of statements), we call <code>codeGen</code> on each statement in the list. It looks like this:</p>
+<pre><code class="cpp">Value* NBlock::codeGen(CodeGenContext&amp; context)
+{
+ StatementList::const_iterator it;
+ Value *last = NULL;
+ <span class="keyword">for</span> (it = statements.begin(); it != statements.end(); it++) {
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Generating code for "</span> &lt;&lt; <span class="keyword">typeid</span>(**it).name() &lt;&lt; <span class="built_in">std</span>::endl;
+ last = (**it).codeGen(context);
+ }
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating block"</span> &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> last;
+}</code></pre>
+<p>We implement this method for all of our nodes, then call it as we go
+down the tree, implicitly walking us through our entire AST. We keep a
+new <code>CodeGenContext</code> class around to tell us where to emit our bytecode.</p>
+<h3>A Big Caveat About LLVM</h3>
+<p>One of the downsides of LLVM is that it’s <em>really</em> hard to
+find useful documentation. Their online tutorial and other such docs are
+ wildly out of date, and there’s barely any information for the C++ API
+unless you really dig for it. If you installed LLVM on your own, check
+the ‘docs’ as it has "more" up to date documentation.</p>
+<p>I’ve found the best way to learn LLVM is by example. There are some
+quick examples of programmatically generating bytecode in the ‘examples’
+ directory of the LLVM archive as well, and there’s also <a href="http://llvm.org/demo/">the LLVM live demo site</a>
+ which can emit C++ API code for a C program as input. This is a great
+way to find out what instructions something like "int x = 5;" will emit.
+ I used the demo tool to implement most of the nodes.</p>
+<p>Without further ado, I’ll be listing both the codegen.h and codegen.cpp files below.</p>
+<p class="note">Listing of codegen.h:</p>
+<pre><code class="cpp"><span class="preprocessor">#include &lt;stack&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Module.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Function.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Type.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/DerivedTypes.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/LLVMContext.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/PassManager.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Instructions.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/CallingConv.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Bitcode/ReaderWriter.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Analysis/Verifier.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Assembly/PrintModulePass.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Support/IRBuilder.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/ModuleProvider.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Target/TargetSelect.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/ExecutionEngine/GenericValue.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/ExecutionEngine/JIT.h&gt;</span>
+<span class="preprocessor">#include &lt;llvm/Support/raw_ostream.h&gt;</span>
+
+<span class="keyword">using</span> <span class="keyword">namespace</span> llvm;
+
+<span class="keyword">class</span> NBlock;
+
+<span class="keyword">class</span> CodeGenBlock {
+<span class="keyword">public</span>:
+ BasicBlock *block;
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">map</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>, Value*&gt;</span> locals;
+};
+
+<span class="keyword">class</span> CodeGenContext {
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">stack</span>&lt;CodeGenBlock *&gt;</span> blocks;
+ Function *mainFunction;
+
+<span class="keyword">public</span>:
+ Module *module;
+ CodeGenContext() { module = <span class="keyword">new</span> Module(<span class="string">"main"</span>, getGlobalContext()); }
+
+ <span class="keyword">void</span> generateCode(NBlock&amp; root);
+ GenericValue runCode();
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">map</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>, Value*&gt;</span>&amp; locals() { <span class="keyword">return</span> blocks.top()-&gt;locals; }
+ BasicBlock *currentBlock() { <span class="keyword">return</span> blocks.top()-&gt;block; }
+ <span class="keyword">void</span> pushBlock(BasicBlock *block) { blocks.push(<span class="keyword">new</span> CodeGenBlock()); blocks.top()-&gt;block = block; }
+ <span class="keyword">void</span> popBlock() { CodeGenBlock *top = blocks.top(); blocks.pop(); <span class="keyword">delete</span> top; }
+};</code></pre>
+<p class="note">Listing of codegen.cpp</p>
+<pre><code class="cpp"><span class="preprocessor">#include "node.h"</span>
+<span class="preprocessor">#include "codegen.h"</span>
+<span class="preprocessor">#include "parser.hpp"</span>
+
+<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;
+
+<span class="comment">/* Compile the AST into a module */</span>
+<span class="keyword">void</span> CodeGenContext::generateCode(NBlock&amp; root)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Generating code...\n"</span>;
+
+ <span class="comment">/* Create the top level interpreter function to call as entry */</span>
+ <span class="stl_container"><span class="built_in">vector</span>&lt;<span class="keyword">const</span> Type*&gt;</span> argTypes;
+ FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()), argTypes, <span class="keyword">false</span>);
+ mainFunction = Function::Create(ftype, GlobalValue::InternalLinkage, <span class="string">"main"</span>, module);
+ BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), <span class="string">"entry"</span>, mainFunction, <span class="number">0</span>);
+
+ <span class="comment">/* Push a new variable/block context */</span>
+ pushBlock(bblock);
+ root.codeGen(*<span class="keyword">this</span>); <span class="comment">/* emit bytecode for the toplevel block */</span>
+ ReturnInst::Create(getGlobalContext(), bblock);
+ popBlock();
+
+ <span class="comment">/* Print the bytecode in a human-readable format
+ to see if our program compiled properly
+ */</span>
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Code is generated.\n"</span>;
+ PassManager pm;
+ pm.add(createPrintModulePass(&amp;outs()));
+ pm.run(*module);
+}
+
+<span class="comment">/* Executes the AST by running the main function */</span>
+GenericValue CodeGenContext::runCode() {
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Running code...\n"</span>;
+ ExistingModuleProvider *mp = <span class="keyword">new</span> ExistingModuleProvider(module);
+ ExecutionEngine *ee = ExecutionEngine::create(mp, <span class="keyword">false</span>);
+ <span class="stl_container"><span class="built_in">vector</span>&lt;GenericValue&gt;</span> noargs;
+ GenericValue v = ee-&gt;runFunction(mainFunction, noargs);
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Code was run.\n"</span>;
+ <span class="keyword">return</span> v;
+}
+
+<span class="comment">/* Returns an LLVM type based on the identifier */</span>
+<span class="keyword">static</span> <span class="keyword">const</span> Type *typeOf(<span class="keyword">const</span> NIdentifier&amp; type)
+{
+ <span class="keyword">if</span> (type.name.compare(<span class="string">"int"</span>) == <span class="number">0</span>) {
+ <span class="keyword">return</span> Type::getInt64Ty(getGlobalContext());
+ }
+ <span class="keyword">else</span> <span class="keyword">if</span> (type.name.compare(<span class="string">"double"</span>) == <span class="number">0</span>) {
+ <span class="keyword">return</span> Type::getDoubleTy(getGlobalContext());
+ }
+ <span class="keyword">return</span> Type::getVoidTy(getGlobalContext());
+}
+
+<span class="comment">/* -- Code Generation -- */</span>
+
+Value* NInteger::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating integer: "</span> &lt;&lt; value &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> ConstantInt::get(Type::getInt64Ty(getGlobalContext()), value, <span class="keyword">true</span>);
+}
+
+Value* NDouble::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating double: "</span> &lt;&lt; value &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> ConstantFP::get(Type::getDoubleTy(getGlobalContext()), value);
+}
+
+Value* NIdentifier::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating identifier reference: "</span> &lt;&lt; name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">if</span> (context.locals().find(name) == context.locals().end()) {
+ <span class="built_in">std</span>::<span class="built_in">cerr</span> &lt;&lt; <span class="string">"undeclared variable "</span> &lt;&lt; name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> NULL;
+ }
+ <span class="keyword">return</span> <span class="keyword">new</span> LoadInst(context.locals()[name], <span class="string">""</span>, <span class="keyword">false</span>, context.currentBlock());
+}
+
+Value* NMethodCall::codeGen(CodeGenContext&amp; context)
+{
+ Function *function = context.module-&gt;getFunction(id.name.c_str());
+ <span class="keyword">if</span> (function == NULL) {
+ <span class="built_in">std</span>::<span class="built_in">cerr</span> &lt;&lt; <span class="string">"no such function "</span> &lt;&lt; id.name &lt;&lt; <span class="built_in">std</span>::endl;
+ }
+ <span class="built_in">std</span>::<span class="stl_container"><span class="built_in">vector</span>&lt;Value*&gt;</span> args;
+ ExpressionList::const_iterator it;
+ <span class="keyword">for</span> (it = arguments.begin(); it != arguments.end(); it++) {
+ args.push_back((**it).codeGen(context));
+ }
+ CallInst *call = CallInst::Create(function, args.begin(), args.end(), <span class="string">""</span>, context.currentBlock());
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating method call: "</span> &lt;&lt; id.name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> call;
+}
+
+Value* NBinaryOperator::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating binary operation "</span> &lt;&lt; op &lt;&lt; <span class="built_in">std</span>::endl;
+ Instruction::BinaryOps instr;
+ <span class="keyword">switch</span> (op) {
+ <span class="keyword">case</span> TPLUS: instr = Instruction::Add; <span class="keyword">goto</span> math;
+ <span class="keyword">case</span> TMINUS: instr = Instruction::Sub; <span class="keyword">goto</span> math;
+ <span class="keyword">case</span> TMUL: instr = Instruction::Mul; <span class="keyword">goto</span> math;
+ <span class="keyword">case</span> TDIV: instr = Instruction::SDiv; <span class="keyword">goto</span> math;
+
+ <span class="comment">/* TODO comparison */</span>
+ }
+
+ <span class="keyword">return</span> NULL;
+math:
+ <span class="keyword">return</span> BinaryOperator::Create(instr, lhs.codeGen(context),
+ rhs.codeGen(context), <span class="string">""</span>, context.currentBlock());
+}
+
+Value* NAssignment::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating assignment for "</span> &lt;&lt; lhs.name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">if</span> (context.locals().find(lhs.name) == context.locals().end()) {
+ <span class="built_in">std</span>::<span class="built_in">cerr</span> &lt;&lt; <span class="string">"undeclared variable "</span> &lt;&lt; lhs.name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> NULL;
+ }
+ <span class="keyword">return</span> <span class="keyword">new</span> StoreInst(rhs.codeGen(context), context.locals()[lhs.name], <span class="keyword">false</span>, context.currentBlock());
+}
+
+Value* NBlock::codeGen(CodeGenContext&amp; context)
+{
+ StatementList::const_iterator it;
+ Value *last = NULL;
+ <span class="keyword">for</span> (it = statements.begin(); it != statements.end(); it++) {
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Generating code for "</span> &lt;&lt; <span class="keyword">typeid</span>(**it).name() &lt;&lt; <span class="built_in">std</span>::endl;
+ last = (**it).codeGen(context);
+ }
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating block"</span> &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> last;
+}
+
+Value* NExpressionStatement::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Generating code for "</span> &lt;&lt; <span class="keyword">typeid</span>(expression).name() &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> expression.codeGen(context);
+}
+
+Value* NVariableDeclaration::codeGen(CodeGenContext&amp; context)
+{
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating variable declaration "</span> &lt;&lt; type.name &lt;&lt; <span class="string">" "</span> &lt;&lt; id.name &lt;&lt; <span class="built_in">std</span>::endl;
+ AllocaInst *alloc = <span class="keyword">new</span> AllocaInst(typeOf(type), id.name.c_str(), context.currentBlock());
+ context.locals()[id.name] = alloc;
+ <span class="keyword">if</span> (assignmentExpr != NULL) {
+ NAssignment assn(id, *assignmentExpr);
+ assn.codeGen(context);
+ }
+ <span class="keyword">return</span> alloc;
+}
+
+Value* NFunctionDeclaration::codeGen(CodeGenContext&amp; context)
+{
+ <span class="stl_container"><span class="built_in">vector</span>&lt;<span class="keyword">const</span> Type*&gt;</span> argTypes;
+ VariableList::const_iterator it;
+ <span class="keyword">for</span> (it = arguments.begin(); it != arguments.end(); it++) {
+ argTypes.push_back(typeOf((**it).type));
+ }
+ FunctionType *ftype = FunctionType::get(typeOf(type), argTypes, <span class="keyword">false</span>);
+ Function *function = Function::Create(ftype, GlobalValue::InternalLinkage, id.name.c_str(), context.module);
+ BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), <span class="string">"entry"</span>, function, <span class="number">0</span>);
+
+ context.pushBlock(bblock);
+
+ <span class="keyword">for</span> (it = arguments.begin(); it != arguments.end(); it++) {
+ (**it).codeGen(context);
+ }
+
+ block.codeGen(context);
+ ReturnInst::Create(getGlobalContext(), bblock);
+
+ context.popBlock();
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"Creating function: "</span> &lt;&lt; id.name &lt;&lt; <span class="built_in">std</span>::endl;
+ <span class="keyword">return</span> function;
+}</code></pre>
+<p>There is certainly a great deal to take in here, however this is the
+part where you should start exploring on your own. I only have a couple
+of notes: </p>
+<ul>
+<li>We use a “stack†of blocks in our CodeGenContext class to keep the
+last entered block (because instructions are added to blocks) </li>
+<li>We also use this stack to keep a <a href="http://en.wikipedia.org/wiki/Symbol_table">symbol table</a> of the local variables in each block. </li>
+<li>Our toy program only knows about variables in its own scope. To
+support the idea of “global†contexts you’d need to search upwards
+through each block in our stack until you found a match to the symbol
+(rather than simply searching the top symbol table). </li>
+<li>Before entering a block we should push the block and when leaving it we should pop it. </li>
+</ul>
+<p>The rest of the details are all related to LLVM, and again, I’m
+hardly an expert on that subject. But at this point, we have all of the
+code we need to compile our toy language and watch it run.</p>
+<p><!--nextpage--><br>
+<!--pagetitle:Building and Running Our Toy Language--></p>
+<h2>Building Our Toy Language</h2>
+<p>We have the code, but how to we build it? LLVM can be complicated to link, fortunately if you installed LLVM you also got an <code>llvm-config</code> binary which returns all of the compiler/linker flags you need.</p>
+<p>We also need to update our main.cpp file from earlier to actually compile and run our code, this time:</p>
+<p class="note">Listing of main.cpp:</p>
+<pre><code class="cpp"><span class="preprocessor">#include &lt;iostream&gt;</span>
+<span class="preprocessor">#include "codegen.h"</span>
+<span class="preprocessor">#include "node.h"</span>
+
+<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;
+
+<span class="keyword">extern</span> <span class="keyword">int</span> yyparse();
+<span class="keyword">extern</span> NBlock* programBlock;
+
+<span class="keyword">int</span> main(<span class="keyword">int</span> argc, <span class="keyword">char</span> **argv)
+{
+ yyparse();
+ <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; programBlock &lt;&lt; <span class="built_in">std</span>::endl;
+
+ CodeGenContext context;
+ context.generateCode(*programBlock);
+ context.runCode();
+
+ <span class="keyword">return</span> <span class="number">0</span>;
+}</code></pre>
+<p>Now all we need to do is compile:</p>
+<pre><code class=" ruby"><span class="variable">$ </span><span class="identifier">g</span>++ -<span class="identifier">o</span> <span class="identifier">parser</span> `<span class="identifier">llvm</span>-<span class="identifier">config</span> --<span class="identifier">libs</span> <span class="identifier">core</span> <span class="identifier">jit</span> <span class="identifier">native</span> --<span class="identifier">cxxflags</span> --<span class="identifier">ldflags</span>` *.<span class="identifier">cpp</span></code></pre>
+<p>You can also grab this Makefile to make things easier:</p>
+<p class="note">Listing of Makefile:</p>
+<pre><code class=" ruby"><span class="identifier">all</span><span class="symbol">:</span> <span class="identifier">parser</span>
+
+<span class="identifier">clean</span><span class="symbol">:</span>
+ <span class="identifier">rm</span> <span class="identifier">parser</span>.<span class="identifier">cpp</span> <span class="identifier">parser</span>.<span class="identifier">hpp</span> <span class="identifier">parser</span> <span class="identifier">tokens</span>.<span class="identifier">cpp</span>
+
+<span class="identifier">parser</span>.<span class="identifier">cpp</span><span class="symbol">:</span> <span class="identifier">parser</span>.<span class="identifier">y</span>
+ <span class="identifier">bison</span> -<span class="identifier">d</span> -<span class="identifier">o</span> <span class="variable">$@</span> <span class="variable">$^</span>
+
+<span class="identifier">parser</span>.<span class="identifier">hpp</span><span class="symbol">:</span> <span class="identifier">parser</span>.<span class="identifier">cpp</span>
+
+<span class="identifier">tokens</span>.<span class="identifier">cpp</span><span class="symbol">:</span> <span class="identifier">tokens</span>.<span class="identifier">l</span> <span class="identifier">parser</span>.<span class="identifier">hpp</span>
+ <span class="identifier">lex</span> -<span class="identifier">o</span> <span class="variable">$@</span> <span class="variable">$^</span>
+
+<span class="identifier">parser</span><span class="symbol">:</span> <span class="identifier">parser</span>.<span class="identifier">cpp</span> <span class="identifier">codegen</span>.<span class="identifier">cpp</span> <span class="identifier">main</span>.<span class="identifier">cpp</span> <span class="identifier">tokens</span>.<span class="identifier">cpp</span>
+ <span class="identifier">g</span>++ -<span class="identifier">o</span> <span class="variable">$@</span> `<span class="identifier">llvm</span>-<span class="identifier">config</span> --<span class="identifier">libs</span> <span class="identifier">core</span> <span class="identifier">jit</span> <span class="identifier">native</span> --<span class="identifier">cxxflags</span> --<span class="identifier">ldflags</span>` *.<span class="identifier">cpp</span></code></pre>
+<h2>Running Our Toy Language</h2>
+<p>Hopefully everything compiled properly. At this point you should have
+ your parser binary that spits out code. Play with it. Remember our
+canonical example? Let’s see what our program does.</p>
+<pre><code class=" javascript">$ echo <span class="string">'int do_math(int a) { int x = a * 5 + 3 } do_math(10)'</span> | ./parser
+<span class="number">0x100a00f10</span>
+Generating code...
+Generating code <span class="keyword">for</span> <span class="number">20</span>NFunctionDeclaration
+Creating variable declaration int a
+Generating code <span class="keyword">for</span> <span class="number">20</span>NVariableDeclaration
+Creating variable declaration int x
+Creating assignment <span class="keyword">for</span> x
+Creating binary operation <span class="number">276</span>
+Creating binary operation <span class="number">274</span>
+Creating integer: <span class="number">3</span>
+Creating integer: <span class="number">5</span>
+Creating identifier reference: a
+Creating block
+Creating <span class="function"><span class="keyword">function</span>: <span class="title">do_math</span>
+<span class="title">Generating</span> <span class="title">code</span> <span class="title">for</span> 20<span class="title">NExpressionStatement</span>
+<span class="title">Generating</span> <span class="title">code</span> <span class="title">for</span> 11<span class="title">NMethodCall</span>
+<span class="title">Creating</span> <span class="title">integer</span>: 10
+<span class="title">Creating</span> <span class="title">method</span> <span class="title">call</span>: <span class="title">do_math</span>
+<span class="title">Creating</span> <span class="title">block</span>
+<span class="title">Code</span> <span class="title">is</span> <span class="title">generated</span>.
+; <span class="title">ModuleID</span> = '<span class="title">main</span>'
+
+<span class="title">define</span> <span class="title">internal</span> <span class="title">void</span> @<span class="title">main</span><span class="params">()</span> {</span>
+entry:
+ %<span class="number">0</span> = call i64 @do_math(i64 <span class="number">10</span>) ; <i64> [#uses=<span class="number">0</span>]
+ ret <span class="keyword">void</span>
+}
+
+define internal i64 @do_math(i64) {
+entry:
+ %a = alloca i64 ; <i64 *=""> [#uses=<span class="number">1</span>]
+ %x = alloca i64 ; <i64 *=""> [#uses=<span class="number">1</span>]
+ %<span class="number">1</span> = add i64 <span class="number">5</span>, <span class="number">3</span> ; <i64> [#uses=<span class="number">1</span>]
+ %<span class="number">2</span> = load i64* %a ; <i64> [#uses=<span class="number">1</span>]
+ %<span class="number">3</span> = mul i64 %<span class="number">2</span>, %<span class="number">1</span> ; <i64> [#uses=<span class="number">1</span>]
+ store i64 %<span class="number">3</span>, i64* %x
+ ret <span class="keyword">void</span>
+}
+Running code...
+Code was run.</i64></i64></i64></i64></i64></i64></code></pre>
+<p><!--nextpage--><br>
+<!--pagetitle:Conclusion--></p>
+<p>Isn’t that pretty cool? I’ll admit it’s probably less satisfying to
+get something running when you just copy paste from a how to guide, but
+getting this running should still be interesting for you. Plus, and this
+ is the best part, this isn’t the end of the guide, it’s just the
+beginning, because this is the part where <em>you</em> start tacking on
+crazy features to this lexer, parser and assembler to create a language
+that you can call your own. You have all the building blocks, and you
+should have a basic idea of how to continue on.</p>
+<p>The code, by the way, is available on Github <a href="http://github.com/lsegal/my_toy_compiler">here</a>.
+ I avoided saying this because the code was not the point of the
+article, but rather going over the code in detail was. If you’re just
+going to grab the code it sort of defeats the purpose of writing your
+own compiler.</p>
+<p>I realize this is a huge article, and there are probably mistakes, so
+ if you run into problems, feel free to send me an email and I’ll make
+adjustments. If you want to share some info, feel free to do that as
+well.</p>
+<p style="text-align:right"></p><div class="multipage"><span class="contentjumplink">Previous Page</span><ol class="contentlist"><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/">Introduction</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/2/">Getting Started</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/3/">Step1. Lexical Analysis with Flex</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/4/">Step 2. Semantic Parsing with Bison</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/5/">Generating Flex and Bison Code</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/6/">Step 3. Assembling the AST with LLVM</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/7/">Building and Running Our Toy Language</a></li><li><a class="contentlist" href="http://gnuu.org/2009/09/18/writing-your-own-toy-compiler/8/">Conclusion</a></li><li class="contentlistall">View All</li></ol><span class="contentjumplink">Next Page</span></div><p></p> </div>
+
+ <div class="talktome">Questions? Comments? Follow me on Twitter (<a href="http://twitter.com/lsegal">@lsegal</a>) or <a href="mailto:lsegal@soen.ca">email me</a>.</div>
+ </div>
+
+
+
+
+ <div id="copyright">Copyright © 2009 Loren Segal. <small>I can't guarantee this works in IE6.</small></div>
+ </div>
+ <div id="nav">
+ <div class="section about">
+ <h2>About</h2>
+ <p>
+ <img alt="Me" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/twitter_icon.jpg" align="right">
+ I'm <strong>Loren Segal</strong>, a programmer, Rubyist, author of <a href="http://yard.soen.ca/" title="Yay! A Ruby Documentation Tool">YARD</a>, musician, photographer, writer and <a href="http://github.com/amazonwebservices">Amazon Web Services SDK Developer</a> living in <strong>Seattle</strong></p>
+ </div>
+
+ <div class="section articles">
+ <h2>Other Articles</h2>
+
+ <ul>
+ <li><a href="http://gnuu.org/2013/06/20/the-audio-diaries-ch-2-using-rubyaudio/" title="The Audio Diaries Ch. 2 – Using RubyAudio">The Audio Diaries Ch. 2 – Using RubyAudio </a></li>
+ <li><a href="http://gnuu.org/2013/06/18/the-audio-diaries-ch-1-may-i-have-your-attenuation-please/" title="The Audio Diaries Ch. 1 – May I Have Your Attenuation Please?">The Audio Diaries Ch. 1 – May I Have Your Attenuation Please? </a></li>
+ <li><a href="http://gnuu.org/2013/01/06/dependency-injection-is-not-just-for-testing/" title="Dependency Injection is NOT Just for Testing">Dependency Injection is NOT Just for Testing </a></li>
+ <li><a href="http://gnuu.org/2012/04/30/yard-0-8-0-released/" title="YARD 0.8.0 Released!">YARD 0.8.0 Released! </a></li>
+ <li><a href="http://gnuu.org/page/1">More...</a></li>
+ </ul>
+ </div>
+
+ <div class="section twitter">
+ <h2>
+ <span class="title">Twitter Feed</span> <a class="follow" href="http://twitter.com/lsegal">follow me</a>
+ <span style="color: #111; clear: both">.</span>
+ </h2>
+
+ <div class="twitterapp"><ul class="twitterapplist"></ul></div>
+ </div>
+
+ <div class="section ads">
+ <script type="text/javascript"><!--
+google_ad_client = "pub-2497446755186719";
+/* 180x150, created 3/27/10 */
+google_ad_slot = "5914781461";
+google_ad_width = 180;
+google_ad_height = 150;
+//-->
+</script>
+<script type="text/javascript" src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/show_ads.js">
+</script><ins style="display:inline-table;border:none;height:150px;margin:0;padding:0;position:relative;visibility:visible;width:180px"><ins id="aswift_0_anchor" style="display:block;border:none;height:150px;margin:0;padding:0;position:relative;visibility:visible;width:180px"><iframe marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" onload="var i=this.id,s=window.google_iframe_oncopy,H=s&amp;&amp;s.handlers,h=H&amp;&amp;H[i],w=this.contentWindow,d;try{d=w.document}catch(e){}if(h&amp;&amp;d&amp;&amp;(!d.body||!d.body.firstChild)){if(h.call){setTimeout(h,0)}else if(h.match){w.location.replace(h)}}" id="aswift_0" name="aswift_0" style="left:0;position:absolute;top:0;" frameborder="0" height="150" scrolling="no" width="180"></iframe></ins></ins>
+ </div>
+ </div>
+ <br style="clear:both">
+ </div>
+
+
+ <!-- clicky -->
+ <script type="text/javascript">
+var domainy = location.protocol == "https:" ? "https://static.getclicky.com" : "http://static.getclicky.com";
+document.write(unescape("%3Cscript src='" + domainy + "/134242.js' type='text/javascript'%3E%3C/script%3E"));
+</script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/134242.js" type="text/javascript"></script>
+<noscript><p><img alt="Clicky" width="1" height="1" src="http://static.getclicky.com/134242-db17.gif" /></p></noscript>
+
+
+ <!-- google analytics -->
+ <script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script><script src="Writing%20Your%20Own%20Toy%20Compiler%20Using%20Flex,%20Bison%20and%20LLVM%20%28gnuu.org%29_files/ga.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("UA-7172246-1");
+ pageTracker._trackPageview();
+ } catch(err) {}
+ </script>
+
+</body></html> \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/134242.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/134242.js
new file mode 100644
index 0000000..fc8ef4f
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/134242.js
@@ -0,0 +1 @@
+var clicky_obj=clicky_obj||(function(){var instance=null;function _ins(){var _self=this,site_ids=[],pageviews_fired=[],monitors=0,setup=0,ossassets=0,ossdata=0;this.domain='http://in.getclicky.com';if(document.location.protocol==='https:'){this.domain='https://in.getclicky.com';this.secure=1;}this.site_id_exists=function(site_id){for(var s in site_ids)if(site_ids[s]==site_id)return true;return false;};this.init=function(site_id){if(_self.site_id_exists(site_id))return;site_ids.push(site_id);if(!setup){setup=1;setTimeout(_self.setup,100);}};this.setup=function(){if(location.hash.match(/^#_heatmap/))_self.heatmap();_self.set_referrer(document.referrer);setTimeout(_self.advanced,1000);_self.start_monitors();if(!clicky_custom.pageview_disable){if(window.olark){olark('api.boot.onIdentityReady',function(s,v,c){_self.olark(s,v,c,1);});setTimeout(_self.pageview,2000);}else{_self.pageview();}}};this.base=function(site_id_index,type){var url=_self.domain+'/in.php?site_id='+site_ids[site_id_index];if(type=='ping')return url;url+="&res="+screen.width+"x"+screen.height+"&lang="+(navigator.language||navigator.browserLanguage||'en').substr(0,2)+(_self.secure?"&secure=1":"");if(clicky_custom.session){for(var i in clicky_custom.session){if(clicky_custom.session.hasOwnProperty&&clicky_custom.session.hasOwnProperty(i))url+="&custom["+_self.enc(i)+"]="+_self.enc(clicky_custom.session[i]);}}return url;};this.set_referrer=function(r){_self.ref=r?(RegExp("^https?://[^/]*"+location.host.replace(/^www\./i,"")+"/","i").test(r)?'':this.enc(r)):'';};this.olark=function(s,v,c,do_pageview){var o=s+','+v+','+c,c=_self.get_cookie('clicky_olark');if(c&&c==o){if(do_pageview)_self.pageview();return;}else{if(c)_self.set_cookie('clicky_olark',c,-3600);_self.set_cookie('clicky_olark',o,600);c=_self.get_cookie('clicky_olark');}if(do_pageview||pageviews_fired.length==0){_self.pageview('&olark='+o);}else if(c){_self.beacon('ping','&olark='+o);}};this.pageview=function(extra){var href=_self.get_href();if(_self.facebook_is_lame(href))return;_self.beacon('','&href='+_self.enc(href)+'&title='+_self.enc(clicky_custom.title||document.title)+'&ref='+(_self.ref||'')+(extra||''),1);for(var p=0;p<site_ids.length;p++){if(!_self.is_pageview_fired(site_ids[p])){pageviews_fired.push(site_ids[p]);}}};this.get_href=function(enc){var href=clicky_custom.href||'';if(!href){if(clicky_custom.iframe&&self!=top){_self.set_referrer(top.document.referrer);href=top.location.pathname+top.location.search;if(!clicky_custom.title)clicky_custom.title=top.document.title;}else if(location.hash.match(/utm_/i)){href=location.pathname+(location.search?location.search+'&':'?')+location.hash.substr(1);}else href=location.pathname+location.search;}return enc?_self.enc(href):href;};this.log=function(href,title,type){if(_self.facebook_is_lame(href))return;if(type=='pageview')href=href.replace(/^https?:\/\/([^\/]+)/i,'');var o={'type':(type||'click'),'href':href,'title':(title||'')};if(!_self.queue_add(o))_self.beacon(type,o);};this.queue_ok=function(){return window.JSON&&typeof JSON=='object'&&JSON.stringify&&JSON.parse&&!clicky_custom.cookies_disable&&!window.Prototype;};this.queue_add=function(o){if(!_self.queue_ok())return false;if(o.type.match(/pageview|download|outbound/i))return false;var q=_self.queue_get();try{if(o.type=='heatmap'){q.heatmap.push(o);}else{q.events.push(o);}}catch(e){if(_self.debug)console.log(e);return false;}_self.queue_set(q);return true;};this.queue_reset=function(){_self.queue_set(_self.queue_default());};this.queue_get=function(){var q=_self.get_cookie('_eventqueue');return q?JSON.parse(decodeURIComponent(q)):_self.queue_default();};this.queue_set=function(q,ex){for(var i=0;i<q.heatmap.length;i++)q.heatmap[i].href=_self.enc(q.heatmap[i].href);for(var i=0;i<q.events.length;i++){q.events[i].href=_self.enc(q.events[i].href);if(q.events[i].title)q.events[i].title=_self.enc(q.events[i].title);}_self.set_cookie('_eventqueue',encodeURIComponent(JSON.stringify(q)),(ex||600));};this.queue_default=function(){return{'heatmap':[],'events':[]};};this.queue_process=function(){var q=_self.queue_get();try{if(q.heatmap.length||q.events.length)_self.queue_reset();for(var i=0,s='';i<q.heatmap.length;i++){var o=q.heatmap[i];if(!o.href||!o.x||!o.y||!o.w)return;s+='&heatmap[]='+_self.enc(o.href)+'|'+o.x+'|'+o.y+'|'+o.w;}if(s)_self.beacon('heatmap',s);while(q.events.length)_self.beacon('',q.events.shift());}catch(e){if(_self.debug)console.log(e);}};this.heatmap_xy=function(e){var x,y;if(e.pageX){x=e.pageX;y=e.pageY;}else if(e.clientX){x=e.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;y=e.clientY+document.body.scrollTop+document.documentElement.scrollTop;}else return;var w=_self.doc_wh(),href=_self.get_href();if(!clicky_custom.heatmap_disable)_self.queue_add({'type':'heatmap','x':x,'y':y,'w':w.w,'href':href});};this.doc_wh=function(){var db=document.body,de=document.documentElement;return{w:window.innerWidth||de.clientWidth||1024,h:Math.max(db.scrollHeight,db.offsetHeight,de.clientHeight,de.scrollHeight,de.offsetHeight)}};this.heatmap=function(date,sub,subitem){if(window._heatmap_destroy)_heatmap_destroy();if(window.heatmapFactory)_self.heatmap_data(date,sub,subitem);else{_self.inject('//static.getclicky.com/inc/javascript/heatmap.js');setTimeout('_genericStats.heatmap("'+(date||'')+'","'+(sub||'')+'","'+(subitem||'')+'")',1000);}};this.heatmap_data=function(date,sub,subitem){wh=_self.doc_wh();_self.inject('//clicky.com/ajax/onsitestats/heatmap?'+'site_id='+site_ids[0]+'&href='+_self.get_href(1)+'&domain='+location.hostname+'&w='+wh.w+'&h='+wh.h+(location.hash.match(/^#_heatmap/)?location.hash.replace(/^#_heatmap/,''):'')+(date?'&date='+date:'')+(sub?'&sub='+sub:'')+(subitem?'&subitem='+subitem:'')+'&x='+Math.random());};this.heatmap_override=function(e){if(document.querySelectorAll){var nodes=document.querySelectorAll(e);for(var n=0;n<nodes.length;n++){_self.add_event(nodes[n],'click',_self.heatmap_xy);}}};this.onsitestats=function(refresh,reset){if(ossassets){if(window.jQuery&&window._OSS){if(_self.jqnc){jQuery.noConflict();_self.jqnc=0;}if(!ossdata||refresh){ossdata=1;_self.inject('//clicky.com/ajax/onsitestats/?site_id='+site_ids[0]+'&href='+_self.get_href(1)+'&domain='+location.hostname+(refresh?'&refresh=1':'')+(reset?'&reset=1':'')+'&x='+Math.random());}}else setTimeout(_self.onsitestats,200);}else{ossassets=1;_self.inject('//static.getclicky.com/inc/onsitestats.css','css');_self.inject('//static.getclicky.com/inc/javascript/onsitestats.js');if(!window.jQuery){_self.inject('//static.getclicky.com/inc/javascript/jquery.js');_self.jqnc=1;}setTimeout(_self.onsitestats,1000);}};this.start_monitors=function(){if(!monitors){monitors=1;if(_self.queue_ok()){_self.queue_process();setInterval(_self.queue_process,5000);}_self.hm_monitor();}};this.hm_monitor=function(){if(document.body){_self.add_event(document.body,'click',_self.heatmap_xy);if(clicky_custom.heatmap_objects){if(typeof clicky_custom.heatmap_objects==="object"){for(var hmo in clicky_custom.heatmap_objects)_self.heatmap_override(clicky_custom.heatmap_objects[hmo]);}else{_self.heatmap_override(clicky_custom.heatmap_objects);}}}else setTimeout(_self.hm_monitor,1000);};this.facebook_is_lame=function(href){return href.match(/fb_xd_fragment|fb_xd_bust|fbc_channel/i);};this.video=function(action,time,url,title){if(!url||!action)return false;_self.beacon('video','&video[action]='+action+'&video[time]='+(time||0)+'&href='+_self.enc(url)+(title?'&title='+_self.enc(title):''));};this.goal=function(id,revenue,noq){if(!id)return;var goal=(typeof id=='number'||id.match(/^[0-9]+$/))?'[id]='+id:'[name]='+_self.enc(id);goal={type:'goal',query:'&goal'+goal+(revenue?'&goal[revenue]='+revenue:'')};if(noq||!_self.queue_add(goal))_self.beacon('goal',goal);};this.beacon=function(type,q,called_by_pageview){q=q||'';type=type||'pageview';if(typeof q=='object'){if(q.type)type=q.type;if(q.type=='goal'&&q.query){q=q.query;}else{var temp='';for(var i in q){if(i!='type'&&q.hasOwnProperty&&q.hasOwnProperty(i))temp+='&'+i+'='+_self.enc(q[i]);}q=temp;delete temp;}}var jsuid='',goal='',split='';jsuid=_self.get_cookie('_jsuid');if(!jsuid){_self.set_cookie('_jsuid',_self.randy());jsuid=_self.get_cookie('_jsuid');}if(type!='heatmap'&&type!='ping'){if(clicky_custom.goal){if(typeof clicky_custom.goal=='object'){for(var i in clicky_custom.goal){if(clicky_custom.goal.hasOwnProperty&&clicky_custom.goal.hasOwnProperty(i))goal+='&goal['+_self.enc(i)+']='+_self.enc(clicky_custom.goal[i]);}}else{goal='&goal='+_self.enc(clicky_custom.goal);}clicky_custom.goal='';}if(clicky_custom.split){for(var i in clicky_custom['split']){if(clicky_custom['split'].hasOwnProperty&&clicky_custom['split'].hasOwnProperty(i)){if(i=='goal'&&typeof clicky_custom['split'].goal=='object'){for(var j=0,l=clicky_custom['split'].goal.length;j<l;j++){split+='&split[goal][]='+clicky_custom.split.goal[j];}}else split+='&split['+_self.enc(i)+']='+_self.enc(clicky_custom.split[i]);}}clicky_custom.split='';}}for(var site_id_index=0;site_id_index<site_ids.length;site_id_index++){var site_id=site_ids[site_id_index];if(_self.get_cookie('no_tracky_'+site_id))continue;if(_self.get_cookie('unpoco_'+site_id)&&(_self.secure||type!='pageview'))continue;if(type=='heatmap'&&_self.get_cookie('heatmaps_g2g_'+site_id)!='yes')continue;if(called_by_pageview&&type=='pageview'&&_self.is_pageview_fired(site_id))continue;_self.inject(_self.base(site_id_index,type)+'&type='+type+q+goal+split+(jsuid?'&jsuid='+jsuid:'')+(_self.get_cookie('unpoco_'+site_id)?'&upset':'')+(_self.get_cookie('heatmaps_g2g_'+site_id)?'&hmset':'')+(clicky_custom.cookies_disable?'&noc':'')+'&mime=js&x='+Math.random()+'');}if(type=='outbound'||type=='download')_self.pause();_self.ref='';_self.ping_start();};this.inject=function(src,type){type=type||'js';if(type=='js'){var s=document.createElement('script');s.type='text/javascript';s.async=true;s.src=src;}else if(type=='css'){var s=document.createElement('link');s.type='text/css';s.rel='stylesheet';s.href=src;}(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(s);};this.is_pageview_fired=function(site_id){for(var p=0;p<pageviews_fired.length;p++)if(pageviews_fired[p]==site_id)return true;return false;};this.ping=function(){_self.beacon('ping');};this.ping_set=function(){var pingy=setInterval(_self.ping,120000);setTimeout(function(){clearInterval(pingy);},_self.ps_stop*1000);_self.ping();};this.ping_start=function(){if(clicky_custom.ping_disable||_self.pinging)return;_self.pinging=1;_self.ps_stop=(clicky_custom.timeout&&clicky_custom.timeout>=5&&clicky_custom.timeout<=240)?((clicky_custom.timeout*60)-120)+5:485;setTimeout(_self.ping,30000);setTimeout(_self.ping,60000);setTimeout(_self.ping_set,120000);};this.get_cookie=function(name){var ca=document.cookie.split(';');for(var i=0,l=ca.length;i<l;i++){if(ca[i].match(new RegExp("\\b"+name+"=")))return decodeURIComponent(ca[i].split(name+'=')[1]);}return'';};this.set_cookie=function(name,value,expires){if(clicky_custom.cookies_disable)return false;var ex=new Date;ex.setTime(ex.getTime()+(expires||20*365*86400)*1000);document.cookie=name+"="+value+";expires="+ex.toGMTString()+";path=/;domain="+(clicky_custom.cookie_domain||"."+location.hostname.replace(/^www\./i,""))+";";};this.randy=function(){return Math.round(Math.random()*4294967295);};this.pause=function(x){var now=new Date();var stop=now.getTime()+(x||clicky_custom.timer||500);while(now.getTime()<stop)var now=new Date();};this.enc=function(e){return window.encodeURIComponent?encodeURIComponent(e):escape(e);};this.add_event=function(o,type,func){if(o.addEventListener){o.addEventListener(type,func,false);}else if(o.attachEvent){o.attachEvent("on"+type,func);}};this.download=function(e){_self.adv_log(e,"download");};this.outbound=function(e){_self.adv_log(e,"outbound");};this.click=function(e){_self.adv_log(e,"click");};this.adv_log=function(e,type){var obj=_self.get_target(e);_self.log(_self.adv_href(obj),_self.adv_text(obj),type);};this.adv_text=function(e){do{var txt=e.text?e.text:e.innerText;if(txt)return txt;if(e.alt)return e.alt;if(e.title)return e.title;if(e.src)return e.src;e=_self.get_parent(e);}while(e);return"";};this.adv_href=function(e){do{if(e.href&&!e.src)return e.href;e=_self.get_parent(e);}while(e);return"";};this.get_parent=function(e){return e.parentElement||e.parentNode;};this.get_target=function(e){if(!e)var e=window.event;var t=e.target?e.target:e.srcElement;if(t.nodeType&&t.nodeType==3)t=t.parentNode;return t;};this.advanced=function(){if(clicky_custom.advanced_disable)return;var is_link=new RegExp("^(https?|ftp|telnet|mailto|tel):","i");var is_link_internal=new RegExp("^https?:\/\/(.*)"+location.host.replace(/^www\./i,""),"i");var is_download=new RegExp("\\.(7z|aac|apk|avi|cab|csv|dmg|doc(x|m|b)?|epub|exe|flv|gif|gz|jpe?g|js|m4a|mp(3|4|e?g)|mobi|mov|msi|ods|pdf|phps|png|ppt(x|m|b)?|rar|rtf|sea|sit|tar|torrent|txt|wma|wmv|xls(x|m|b)?|xml|zip)$","i");var a=document.getElementsByTagName("a");for(var i=0;i<a.length;i++){if(a[i].className.match(/clicky_log/i)){if(a[i].className.match(/clicky_log_download/i)){_self.add_event(a[i],"mousedown",_self.download);}else if(a[i].className.match(/clicky_log_outbound/i)){_self.add_event(a[i],"mousedown",_self.outbound);}else{_self.add_event(a[i],"mousedown",_self.click);}}else{if(is_link.test(a[i].href)&&!a[i].className.match(/clicky_ignore/i)){if(is_download.test(a[i].href)){_self.add_event(a[i],"mousedown",_self.download);}else if(!is_link_internal.test(a[i].href)){_self.add_event(a[i],"mousedown",_self.outbound);}else if(clicky_custom.outbound_pattern){var p=clicky_custom.outbound_pattern;if(typeof p=='object'){for(var j=0;j<p.length;j++){if(_self.outbound_pattern_match(a[i].href,p[j])){_self.add_event(a[i],"mousedown",_self.outbound);break;}}}else if(typeof p=='string'){if(_self.outbound_pattern_match(a[i].href,p))_self.add_event(a[i],"mousedown",_self.outbound);}}}}}};this.outbound_pattern_match=function(href,pattern){return RegExp(pattern.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")).test(href);};}return new function(){this.getInstance=function(){if(instance==null){instance=new _ins();instance.constructor=null;}return instance;}}})();var clicky=clicky_obj.getInstance();if(!window.clicky_custom)var clicky_custom={};if(window.clicky_page_title)clicky_custom.title=clicky_page_title;if(window.clicky_advanced_disable)clicky_custom.advanced_disable=1;if(window.clicky_pause_timer)clicky_custom.timer=clicky_pause_timer;if(window.clicky_custom_session)clicky_custom.session=clicky_custom_session;if(window.clicky_goal)clicky_custom.goal=clicky_goal;if(clicky_custom.no_cookies)clicky_custom.cookies_disable=1;if(window.async_site_id)var clicky_site_id=async_site_id;if(window.clicky_site_id){var clicky_site_ids=clicky_site_ids||[];clicky_site_ids.push(clicky_site_id);}if(window.clicky_site_ids){clicky_custom.async=1;while(clicky_site_ids.length)clicky.init(clicky_site_ids.shift());}var _genericStats=clicky,_genericStatsCustom=clicky_custom;_genericStats.init(134242); \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ClassDiagram.png b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ClassDiagram.png
new file mode 100644
index 0000000..5902c55
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ClassDiagram.png
Binary files differ
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ga.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ga.js
new file mode 100644
index 0000000..6e13096
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/ga.js
@@ -0,0 +1,64 @@
+(function(){var aa=encodeURIComponent,ba=Infinity,ca=setTimeout,da=isNaN,m=Math,ea=decodeURIComponent;function ha(a,b){return a.name=b}
+var n="push",ia="test",ja="slice",p="replace",ka="load",la="floor",ma="charAt",na="value",q="indexOf",oa="match",pa="port",qa="createElement",ra="path",r="name",g="getTime",u="host",v="toString",w="length",x="prototype",sa="clientWidth",y="split",ta="stopPropagation",ua="scope",z="location",va="search",A="protocol",wa="clientHeight",xa="href",B="substring",ya="apply",za="navigator",C="join",D="toLowerCase",E;function Aa(a,b){switch(b){case 0:return""+a;case 1:return 1*a;case 2:return!!a;case 3:return 1E3*a}return a}function Ba(a){return"function"==typeof a}function Ca(a){return void 0!=a&&-1<(a.constructor+"")[q]("String")}function F(a,b){return void 0==a||"-"==a&&!b||""==a}function Da(a){if(!a||""==a)return"";for(;a&&-1<" \n\r\t"[q](a[ma](0));)a=a[B](1);for(;a&&-1<" \n\r\t"[q](a[ma](a[w]-1));)a=a[B](0,a[w]-1);return a}function Ea(){return m.round(2147483647*m.random())}function Fa(){}
+function G(a,b){if(aa instanceof Function)return b?encodeURI(a):aa(a);H(68);return escape(a)}function I(a){a=a[y]("+")[C](" ");if(ea instanceof Function)try{return ea(a)}catch(b){H(17)}else H(68);return unescape(a)}var Ga=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent&&a.attachEvent("on"+b,c)},Ha=function(a,b,c,d){a.removeEventListener?a.removeEventListener(b,c,!!d):a.detachEvent&&a.detachEvent("on"+b,c)};
+function Ia(a,b){if(a){var c=J[qa]("script");c.type="text/javascript";c.async=!0;c.src=a;c.id=b;var d=J.getElementsByTagName("script")[0];d.parentNode.insertBefore(c,d);return c}}function K(a){return a&&0<a[w]?a[0]:""}function L(a){var b=a?a[w]:0;return 0<b?a[b-1]:""}var Ja=function(){this.prefix="ga.";this.R={}};Ja[x].set=function(a,b){this.R[this.prefix+a]=b};Ja[x].get=function(a){return this.R[this.prefix+a]};Ja[x].contains=function(a){return void 0!==this.get(a)};function Ka(a){0==a[q]("www.")&&(a=a[B](4));return a[D]()}function La(a,b){var c,d={url:a,protocol:"http",host:"",path:"",d:new Ja,anchor:""};if(!a)return d;c=a[q]("://");0<=c&&(d.protocol=a[B](0,c),a=a[B](c+3));c=a[va]("/|\\?|#");if(0<=c)d.host=a[B](0,c)[D](),a=a[B](c);else return d.host=a[D](),d;c=a[q]("#");0<=c&&(d.anchor=a[B](c+1),a=a[B](0,c));c=a[q]("?");0<=c&&(Na(d.d,a[B](c+1)),a=a[B](0,c));d.anchor&&b&&Na(d.d,d.anchor);a&&"/"==a[ma](0)&&(a=a[B](1));d.path=a;return d}
+function Oa(a,b){function c(a){var b=(a.hostname||"")[y](":")[0][D](),c=(a[A]||"")[D](),c=1*a[pa]||("http:"==c?80:"https:"==c?443:"");a=a.pathname||"";0==a[q]("/")||(a="/"+a);return[b,""+c,a]}var d=b||J[qa]("a");d.href=J[z][xa];var e=(d[A]||"")[D](),f=c(d),Be=d[va]||"",k=e+"//"+f[0]+(f[1]?":"+f[1]:"");0==a[q]("//")?a=e+a:0==a[q]("/")?a=k+a:a&&0!=a[q]("?")?0>a[y]("/")[0][q](":")&&(a=k+f[2][B](0,f[2].lastIndexOf("/"))+"/"+a):a=k+f[2]+(a||Be);d.href=a;e=c(d);return{protocol:(d[A]||"")[D](),host:e[0],
+port:e[1],path:e[2],Oa:d[va]||"",url:a||""}}function Na(a,b){function c(b,c){a.contains(b)||a.set(b,[]);a.get(b)[n](c)}for(var d=Da(b)[y]("&"),e=0;e<d[w];e++)if(d[e]){var f=d[e][q]("=");0>f?c(d[e],"1"):c(d[e][B](0,f),d[e][B](f+1))}}function Pa(a,b){if(F(a)||"["==a[ma](0)&&"]"==a[ma](a[w]-1))return"-";var c=J.domain;return a[q](c+(b&&"/"!=b?b:""))==(0==a[q]("http://")?7:0==a[q]("https://")?8:0)?"0":a};var Qa=0;function Ra(a,b,c){1<=Qa||1<=100*m.random()||(a=["utmt=error","utmerr="+a,"utmwv=5.4.3","utmn="+Ea(),"utmsp=1"],b&&a[n]("api="+b),c&&a[n]("msg="+G(c[B](0,100))),M.w&&a[n]("aip=1"),Sa(a[C]("&")),Qa++)};var Ta=0,Ua={};function N(a){return Va("x"+Ta++,a)}function Va(a,b){Ua[a]=!!b;return a}
+var Wa=N(),Xa=Va("anonymizeIp"),Ya=N(),$a=N(),ab=N(),bb=N(),O=N(),P=N(),cb=N(),db=N(),eb=N(),fb=N(),gb=N(),hb=N(),ib=N(),jb=N(),kb=N(),lb=N(),nb=N(),ob=N(),pb=N(),qb=N(),rb=N(),sb=N(),tb=N(),ub=N(),vb=N(),wb=N(),xb=N(),yb=N(),zb=N(),Ab=N(),Bb=N(),Cb=N(),Db=N(),Eb=N(),Fb=N(!0),Gb=Va("currencyCode"),Hb=Va("page"),Ib=Va("title"),Jb=N(),Kb=N(),Lb=N(),Mb=N(),Nb=N(),Ob=N(),Pb=N(),Qb=N(),Rb=N(),Q=N(!0),Sb=N(!0),Tb=N(!0),Ub=N(!0),Vb=N(!0),Wb=N(!0),Zb=N(!0),$b=N(!0),ac=N(!0),bc=N(!0),cc=N(!0),R=N(!0),dc=N(!0),
+ec=N(!0),fc=N(!0),gc=N(!0),hc=N(!0),ic=N(!0),jc=N(!0),S=N(!0),kc=N(!0),lc=N(!0),mc=N(!0),nc=N(!0),oc=N(!0),pc=N(!0),qc=N(!0),rc=Va("campaignParams"),sc=N(),tc=Va("hitCallback"),uc=N();N();var vc=N(),wc=N(),xc=N(),yc=N(),zc=N(),Ac=N(),Bc=N(),Cc=N(),Dc=N(),Ec=N(),Fc=N(),Gc=N(),Hc=N(),Ic=N();N();var Mc=N(),Nc=N(),Oc=N(),Oe=Va("uaName"),Pe=Va("uaDomain"),Qe=Va("uaPath");var Re=function(){function a(a,c,d){T($[x],a,c,d)}a("_createTracker",$[x].r,55);a("_getTracker",$[x].oa,0);a("_getTrackerByName",$[x].u,51);a("_getTrackers",$[x].pa,130);a("_anonymizeIp",$[x].aa,16);a("_forceSSL",$[x].la,125);a("_getPlugin",Pc,120)},Se=function(){function a(a,c,d){T(U[x],a,c,d)}Qc("_getName",$a,58);Qc("_getAccount",Wa,64);Qc("_visitCode",Q,54);Qc("_getClientInfo",ib,53,1);Qc("_getDetectTitle",lb,56,1);Qc("_getDetectFlash",jb,65,1);Qc("_getLocalGifPath",wb,57);Qc("_getServiceMode",
+xb,59);V("_setClientInfo",ib,66,2);V("_setAccount",Wa,3);V("_setNamespace",Ya,48);V("_setAllowLinker",fb,11,2);V("_setDetectFlash",jb,61,2);V("_setDetectTitle",lb,62,2);V("_setLocalGifPath",wb,46,0);V("_setLocalServerMode",xb,92,void 0,0);V("_setRemoteServerMode",xb,63,void 0,1);V("_setLocalRemoteServerMode",xb,47,void 0,2);V("_setSampleRate",vb,45,1);V("_setCampaignTrack",kb,36,2);V("_setAllowAnchor",gb,7,2);V("_setCampNameKey",ob,41);V("_setCampContentKey",tb,38);V("_setCampIdKey",nb,39);V("_setCampMediumKey",
+rb,40);V("_setCampNOKey",ub,42);V("_setCampSourceKey",qb,43);V("_setCampTermKey",sb,44);V("_setCampCIdKey",pb,37);V("_setCookiePath",P,9,0);V("_setMaxCustomVariables",yb,0,1);V("_setVisitorCookieTimeout",cb,28,1);V("_setSessionCookieTimeout",db,26,1);V("_setCampaignCookieTimeout",eb,29,1);V("_setReferrerOverride",Jb,49);V("_setSiteSpeedSampleRate",Dc,132);a("_trackPageview",U[x].Fa,1);a("_trackEvent",U[x].F,4);a("_trackPageLoadTime",U[x].Ea,100);a("_trackSocial",U[x].Ga,104);a("_trackTrans",U[x].Ia,
+18);a("_sendXEvent",U[x].t,78);a("_createEventTracker",U[x].ia,74);a("_getVersion",U[x].qa,60);a("_setDomainName",U[x].B,6);a("_setAllowHash",U[x].va,8);a("_getLinkerUrl",U[x].na,52);a("_link",U[x].link,101);a("_linkByPost",U[x].ua,102);a("_setTrans",U[x].za,20);a("_addTrans",U[x].$,21);a("_addItem",U[x].Y,19);a("_clearTrans",U[x].ea,105);a("_setTransactionDelim",U[x].Aa,82);a("_setCustomVar",U[x].wa,10);a("_deleteCustomVar",U[x].ka,35);a("_getVisitorCustomVar",U[x].ra,50);a("_setXKey",U[x].Ca,83);
+a("_setXValue",U[x].Da,84);a("_getXKey",U[x].sa,76);a("_getXValue",U[x].ta,77);a("_clearXKey",U[x].fa,72);a("_clearXValue",U[x].ga,73);a("_createXObj",U[x].ja,75);a("_addIgnoredOrganic",U[x].W,15);a("_clearIgnoredOrganic",U[x].ba,97);a("_addIgnoredRef",U[x].X,31);a("_clearIgnoredRef",U[x].ca,32);a("_addOrganic",U[x].Z,14);a("_clearOrganic",U[x].da,70);a("_cookiePathCopy",U[x].ha,30);a("_get",U[x].ma,106);a("_set",U[x].xa,107);a("_addEventListener",U[x].addEventListener,108);a("_removeEventListener",
+U[x].removeEventListener,109);a("_addDevId",U[x].V);a("_getPlugin",Pc,122);a("_setPageGroup",U[x].ya,126);a("_trackTiming",U[x].Ha,124);a("_initData",U[x].v,2);a("_setVar",U[x].Ba,22);V("_setSessionTimeout",db,27,3);V("_setCookieTimeout",eb,25,3);V("_setCookiePersistence",cb,24,1);a("_setAutoTrackOutbound",Fa,79);a("_setTrackOutboundSubdomains",Fa,81);a("_setHrefExamineLimit",Fa,80)};function Pc(a){var b=this.plugins_;if(b)return b.get(a)}
+var T=function(a,b,c,d){a[b]=function(){try{return void 0!=d&&H(d),c[ya](this,arguments)}catch(a){throw Ra("exc",b,a&&a[r]),a;}}},Qc=function(a,b,c,d){U[x][a]=function(){try{return H(c),Aa(this.a.get(b),d)}catch(e){throw Ra("exc",a,e&&e[r]),e;}}},V=function(a,b,c,d,e){U[x][a]=function(f){try{H(c),void 0==e?this.a.set(b,Aa(f,d)):this.a.set(b,e)}catch(Be){throw Ra("exc",a,Be&&Be[r]),Be;}}},Te=function(a,b){return{type:b,target:a,stopPropagation:function(){throw"aborted";}}};var Rc=RegExp(/(^|\.)doubleclick\.net$/i),Sc=function(a,b){return Rc[ia](J[z].hostname)?!0:"/"!==b?!1:0!=a[q]("www.google.")&&0!=a[q](".google.")&&0!=a[q]("google.")||-1<a[q]("google.org")?!1:!0},Tc=function(a){var b=a.get(bb),c=a.c(P,"/");Sc(b,c)&&a[ta]()};var Zc=function(){var a={},b={},c=new Uc;this.g=function(a,b){c.add(a,b)};var d=new Uc;this.e=function(a,b){d.add(a,b)};var e=!1,f=!1,Be=!0;this.T=function(){e=!0};this.j=function(a){this[ka]();this.set(sc,a,!0);a=new Vc(this);e=!1;d.execute(this);e=!0;b={};this.n();a.Ja()};this.load=function(){e&&(e=!1,this.Ka(),Wc(this),f||(f=!0,c.execute(this),Xc(this),Wc(this)),e=!0)};this.n=function(){if(e)if(f)e=!1,Xc(this),e=!0;else this[ka]()};this.get=function(c){Ua[c]&&this[ka]();return void 0!==b[c]?b[c]:
+a[c]};this.set=function(c,d,e){Ua[c]&&this[ka]();e?b[c]=d:a[c]=d;Ua[c]&&this.n()};this.Za=function(b){a[b]=this.b(b,0)+1};this.b=function(a,b){var c=this.get(a);return void 0==c||""===c?b:1*c};this.c=function(a,b){var c=this.get(a);return void 0==c?b:c+""};this.Ka=function(){if(Be){var b=this.c(bb,""),c=this.c(P,"/");Sc(b,c)||(a[O]=a[hb]&&""!=b?Yc(b):1,Be=!1)}}};Zc[x].stopPropagation=function(){throw"aborted";};
+var Vc=function(a){var b=this;this.q=0;var c=a.get(tc);this.Ua=function(){0<b.q&&c&&(b.q--,b.q||c())};this.Ja=function(){!b.q&&c&&ca(c,10)};a.set(uc,b,!0)};function $c(a,b){b=b||[];for(var c=0;c<b[w];c++){var d=b[c];if(""+a==d||0==d[q](a+"."))return d}return"-"}
+var bd=function(a,b,c){c=c?"":a.c(O,"1");b=b[y](".");if(6!==b[w]||ad(b[0],c))return!1;c=1*b[1];var d=1*b[2],e=1*b[3],f=1*b[4];b=1*b[5];if(!(0<=c&&0<d&&0<e&&0<f&&0<=b))return!1;a.set(Q,c);a.set(Vb,d);a.set(Wb,e);a.set(Zb,f);a.set($b,b);return!0},cd=function(a){var b=a.get(Q),c=a.get(Vb),d=a.get(Wb),e=a.get(Zb),f=a.b($b,1);return[a.b(O,1),void 0!=b?b:"-",c||"-",d||"-",e||"-",f][C](".")},dd=function(a){return[a.b(O,1),a.b(cc,0),a.b(R,1),a.b(dc,0)][C](".")},ed=function(a,b,c){c=c?"":a.c(O,"1");var d=
+b[y](".");if(4!==d[w]||ad(d[0],c))d=null;a.set(cc,d?1*d[1]:0);a.set(R,d?1*d[2]:10);a.set(dc,d?1*d[3]:a.get(ab));return null!=d||!ad(b,c)},fd=function(a,b){var c=G(a.c(Tb,"")),d=[],e=a.get(Fb);if(!b&&e){for(var f=0;f<e[w];f++){var Be=e[f];Be&&1==Be[ua]&&d[n](f+"="+G(Be[r])+"="+G(Be[na])+"=1")}0<d[w]&&(c+="|"+d[C]("^"))}return c?a.b(O,1)+"."+c:null},gd=function(a,b,c){c=c?"":a.c(O,"1");b=b[y](".");if(2>b[w]||ad(b[0],c))return!1;b=b[ja](1)[C](".")[y]("|");0<b[w]&&a.set(Tb,I(b[0]));if(1>=b[w])return!0;
+b=b[1][y](-1==b[1][q](",")?"^":",");for(c=0;c<b[w];c++){var d=b[c][y]("=");if(4==d[w]){var e={};ha(e,I(d[1]));e.value=I(d[2]);e.scope=1;a.get(Fb)[d[0]]=e}}return!0},hd=function(a,b){var c=Ue(a,b);return c?[a.b(O,1),a.b(ec,0),a.b(fc,1),a.b(gc,1),c][C]("."):""},Ue=function(a){function b(b,e){if(!F(a.get(b))){var f=a.c(b,""),f=f[y](" ")[C]("%20"),f=f[y]("+")[C]("%20");c[n](e+"="+f)}}var c=[];b(ic,"utmcid");b(nc,"utmcsr");b(S,"utmgclid");b(kc,"utmgclsrc");b(lc,"utmdclid");b(mc,"utmdsid");b(jc,"utmccn");
+b(oc,"utmcmd");b(pc,"utmctr");b(qc,"utmcct");return c[C]("|")},id=function(a,b,c){c=c?"":a.c(O,"1");b=b[y](".");if(5>b[w]||ad(b[0],c))return a.set(ec,void 0),a.set(fc,void 0),a.set(gc,void 0),a.set(ic,void 0),a.set(jc,void 0),a.set(nc,void 0),a.set(oc,void 0),a.set(pc,void 0),a.set(qc,void 0),a.set(S,void 0),a.set(kc,void 0),a.set(lc,void 0),a.set(mc,void 0),!1;a.set(ec,1*b[1]);a.set(fc,1*b[2]);a.set(gc,1*b[3]);Ve(a,b[ja](4)[C]("."));return!0},Ve=function(a,b){function c(a){return(a=b[oa](a+"=(.*?)(?:\\|utm|$)"))&&
+2==a[w]?a[1]:void 0}function d(b,c){c?(c=e?I(c):c[y]("%20")[C](" "),a.set(b,c)):a.set(b,void 0)}-1==b[q]("=")&&(b=I(b));var e="2"==c("utmcvr");d(ic,c("utmcid"));d(jc,c("utmccn"));d(nc,c("utmcsr"));d(oc,c("utmcmd"));d(pc,c("utmctr"));d(qc,c("utmcct"));d(S,c("utmgclid"));d(kc,c("utmgclsrc"));d(lc,c("utmdclid"));d(mc,c("utmdsid"))},ad=function(a,b){return b?a!=b:!/^\d+$/[ia](a)};var Uc=function(){this.filters=[]};Uc[x].add=function(a,b){this.filters[n]({name:a,s:b})};Uc[x].execute=function(a){try{for(var b=0;b<this.filters[w];b++)this.filters[b].s.call(W,a)}catch(c){}};function jd(a){100!=a.get(vb)&&a.get(Q)%1E4>=100*a.get(vb)&&a[ta]()}function kd(a){ld(a.get(Wa))&&a[ta]()}function md(a){"file:"==J[z][A]&&a[ta]()}function nd(a){a.get(Ib)||a.set(Ib,J.title,!0);a.get(Hb)||a.set(Hb,J[z].pathname+J[z][va],!0)};var od=new function(){var a=[];this.set=function(b){a[b]=!0};this.Xa=function(){for(var b=[],c=0;c<a[w];c++)a[c]&&(b[m[la](c/6)]=b[m[la](c/6)]^1<<c%6);for(c=0;c<b[w];c++)b[c]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"[ma](b[c]||0);return b[C]("")+"~"}};function H(a){od.set(a)};var W=window,J=document,ld=function(a){var b=W._gaUserPrefs;return b&&b.ioo&&b.ioo()||!!a&&!0===W["ga-disable-"+a]},We=function(a,b){ca(a,b)},pd=function(a){var b=[],c=J.cookie[y](";");a=RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$");for(var d=0;d<c[w];d++){var e=c[d][oa](a);e&&b[n](e[1])}return b},X=function(a,b,c,d,e,f){e=ld(e)?!1:Sc(d,c)?!1:!0;if(e){if(b&&0<=W[za].userAgent[q]("Firefox")){b=b[p](/\n|\r/g," ");e=0;for(var Be=b[w];e<Be;++e){var k=b.charCodeAt(e)&255;if(10==k||13==k)b=b[B](0,e)+"?"+b[B](e+1)}}b&&
+2E3<b[w]&&(b=b[B](0,2E3),H(69));a=a+"="+b+"; path="+c+"; ";f&&(a+="expires="+(new Date((new Date)[g]()+f)).toGMTString()+"; ");d&&(a+="domain="+d+";");J.cookie=a}};var qd,rd,sd=function(){if(!qd){var a={},b=W[za],c=W.screen;a.Q=c?c.width+"x"+c.height:"-";a.P=c?c.colorDepth+"-bit":"-";a.language=(b&&(b.language||b.browserLanguage)||"-")[D]();a.javaEnabled=b&&b.javaEnabled()?1:0;a.characterSet=J.characterSet||J.charset||"-";try{var d;var e=J.documentElement,f=J.body,Be=f&&f[sa]&&f[wa],c=[];e&&(e[sa]&&e[wa])&&("CSS1Compat"===J.compatMode||!Be)?c=[e[sa],e[wa]]:Be&&(c=[f[sa],f[wa]]);d=0>=c[0]||0>=c[1]?"":c[C]("x");a.Wa=d}catch(k){H(135)}"preview"==b.loadPurpose&&
+H(138);qd=a}},td=function(){sd();for(var a=qd,b=W[za],a=b.appName+b.version+a.language+b.platform+b.userAgent+a.javaEnabled+a.Q+a.P+(J.cookie?J.cookie:"")+(J.referrer?J.referrer:""),b=a[w],c=W.history[w];0<c;)a+=c--^b++;return Yc(a)},ud=function(a){sd();var b=qd;a.set(Lb,b.Q);a.set(Mb,b.P);a.set(Pb,b.language);a.set(Qb,b.characterSet);a.set(Nb,b.javaEnabled);a.set(Rb,b.Wa);if(a.get(ib)&&a.get(jb)){if(!(b=rd)){var c,d,e;d="ShockwaveFlash";if((b=(b=W[za])?b.plugins:void 0)&&0<b[w])for(c=0;c<b[w]&&!e;c++)d=
+b[c],-1<d[r][q]("Shockwave Flash")&&(e=d.description[y]("Shockwave Flash ")[1]);else{d=d+"."+d;try{c=new ActiveXObject(d+".7"),e=c.GetVariable("$version")}catch(f){}if(!e)try{c=new ActiveXObject(d+".6"),e="WIN 6,0,21,0",c.AllowScriptAccess="always",e=c.GetVariable("$version")}catch(Be){}if(!e)try{c=new ActiveXObject(d),e=c.GetVariable("$version")}catch(k){}e&&(e=e[y](" ")[1][y](","),e=e[0]+"."+e[1]+" r"+e[2])}b=e?e:"-"}rd=b;a.set(Ob,rd)}else a.set(Ob,"-")};var vd=function(a){if(Ba(a))this.s=a;else{var b=a[0],c=b.lastIndexOf(":"),d=b.lastIndexOf(".");this.h=this.i=this.l="";-1==c&&-1==d?this.h=b:-1==c&&-1!=d?(this.i=b[B](0,d),this.h=b[B](d+1)):-1!=c&&-1==d?(this.l=b[B](0,c),this.h=b[B](c+1)):c>d?(this.i=b[B](0,d),this.l=b[B](d+1,c),this.h=b[B](c+1)):(this.i=b[B](0,d),this.h=b[B](d+1));this.k=a[ja](1);this.Ma=!this.l&&"_require"==this.h;this.J=!this.i&&!this.l&&"_provide"==this.h}},Y=function(){T(Y[x],"push",Y[x][n],5);T(Y[x],"_getPlugin",Pc,121);T(Y[x],
+"_createAsyncTracker",Y[x].Sa,33);T(Y[x],"_getAsyncTracker",Y[x].Ta,34);this.I=new Ja;this.p=[]};E=Y[x];E.Na=function(a,b,c){var d=this.I.get(a);if(!Ba(d))return!1;b.plugins_=b.plugins_||new Ja;b.plugins_.set(a,new d(b,c||{}));return!0};E.push=function(a){var b=Z.Va[ya](this,arguments),b=Z.p.concat(b);for(Z.p=[];0<b[w]&&!Z.O(b[0])&&!(b.shift(),0<Z.p[w]););Z.p=Z.p.concat(b);return 0};E.Va=function(a){for(var b=[],c=0;c<arguments[w];c++)try{var d=new vd(arguments[c]);d.J?this.O(d):b[n](d)}catch(e){}return b};
+E.O=function(a){try{if(a.s)a.s[ya](W);else if(a.J)this.I.set(a.k[0],a.k[1]);else{var b="_gat"==a.i?M:"_gaq"==a.i?Z:M.u(a.i);if(a.Ma){if(!this.Na(a.k[0],b,a.k[2])){if(!a.Pa){var c=Oa(""+a.k[1]);var d=c[A],e=J[z][A];var f;if(f="https:"==d||d==e?!0:"http:"!=d?!1:"http:"==e){var Be;t:{var k=Oa(J[z][xa]);if(!(c.Oa||0<=c.url[q]("?")||0<=c[ra][q]("://")||c[u]==k[u]&&c[pa]==k[pa]))for(var s="http:"==c[A]?80:443,t=M.S,b=0;b<t[w];b++)if(c[u]==t[b][0]&&(c[pa]||s)==(t[b][1]||s)&&0==c[ra][q](t[b][2])){Be=!0;break t}Be=
+!1}f=Be&&!ld()}f&&(a.Pa=Ia(c.url))}return!0}}else a.l&&(b=b.plugins_.get(a.l)),b[a.h][ya](b,a.k)}}catch(Za){}};E.Sa=function(a,b){return M.r(a,b||"")};E.Ta=function(a){return M.u(a)};var yd=function(){function a(a,b,c,d){void 0==f[a]&&(f[a]={});void 0==f[a][b]&&(f[a][b]=[]);f[a][b][c]=d}function b(a,b,c){if(void 0!=f[a]&&void 0!=f[a][b])return f[a][b][c]}function c(a,b){if(void 0!=f[a]&&void 0!=f[a][b]){f[a][b]=void 0;var c=!0,d;for(d=0;d<Be[w];d++)if(void 0!=f[a][Be[d]]){c=!1;break}c&&(f[a]=void 0)}}function d(a){var b="",c=!1,d,e;for(d=0;d<Be[w];d++)if(e=a[Be[d]],void 0!=e){c&&(b+=Be[d]);for(var c=[],f=void 0,ga=void 0,ga=0;ga<e[w];ga++)if(void 0!=e[ga]){f="";ga!=mb&&void 0==
+e[ga-1]&&(f+=ga[v]()+Za);for(var Cd=e[ga],Jc="",Yb=void 0,Kc=void 0,Lc=void 0,Yb=0;Yb<Cd[w];Yb++)Kc=Cd[ma](Yb),Lc=Ma[Kc],Jc+=void 0!=Lc?Lc:Kc;f+=Jc;c[n](f)}b+=k+c[C](t)+s;c=!1}else c=!0;return b}var e=this,f=[],Be=["k","v"],k="(",s=")",t="*",Za="!",Ma={"'":"'0"};Ma[s]="'1";Ma[t]="'2";Ma[Za]="'3";var mb=1;e.Ra=function(a){return void 0!=f[a]};e.A=function(){for(var a="",b=0;b<f[w];b++)void 0!=f[b]&&(a+=b[v]()+d(f[b]));return a};e.Qa=function(a){if(void 0==a)return e.A();for(var b=a.A(),c=0;c<f[w];c++)void 0==
+f[c]||a.Ra(c)||(b+=c[v]()+d(f[c]));return b};e.f=function(b,c,d){if(!wd(d))return!1;a(b,"k",c,d);return!0};e.o=function(b,c,d){if(!xd(d))return!1;a(b,"v",c,d[v]());return!0};e.getKey=function(a,c){return b(a,"k",c)};e.N=function(a,c){return b(a,"v",c)};e.L=function(a){c(a,"k")};e.M=function(a){c(a,"v")};T(e,"_setKey",e.f,89);T(e,"_setValue",e.o,90);T(e,"_getKey",e.getKey,87);T(e,"_getValue",e.N,88);T(e,"_clearKey",e.L,85);T(e,"_clearValue",e.M,86)};function wd(a){return"string"==typeof a}
+function xd(a){return!("number"==typeof a||void 0!=Number&&a instanceof Number)||m.round(a)!=a||da(a)||a==ba?!1:!0};var zd=function(a){var b=W.gaGlobal;a&&!b&&(W.gaGlobal=b={});return b},Ad=function(){var a=zd(!0).hid;null==a&&(a=Ea(),zd(!0).hid=a);return a},Dd=function(a){a.set(Kb,Ad());var b=zd();if(b&&b.dh==a.get(O)){var c=b.sid;c&&(a.get(ac)?H(112):H(132),a.set(Zb,c),a.get(Sb)&&a.set(Wb,c));b=b.vid;a.get(Sb)&&b&&(b=b[y]("."),a.set(Q,1*b[0]),a.set(Vb,1*b[1]))}};var Ed,Fd=function(a,b,c,d){var e=a.c(bb,""),f=a.c(P,"/");d=void 0!=d?d:a.b(cb,0);a=a.c(Wa,"");X(b,c,f,e,a,d)},Xc=function(a){var b=a.c(bb,"");a.b(O,1);var c=a.c(P,"/"),d=a.c(Wa,"");X("__utma",cd(a),c,b,d,a.get(cb));X("__utmb",dd(a),c,b,d,a.get(db));X("__utmc",""+a.b(O,1),c,b,d);var e=hd(a,!0);e?X("__utmz",e,c,b,d,a.get(eb)):X("__utmz","",c,b,"",-1);(e=fd(a,!1))?X("__utmv",e,c,b,d,a.get(cb)):X("__utmv","",c,b,"",-1)},Wc=function(a){var b=a.b(O,1);if(!bd(a,$c(b,pd("__utma"))))return a.set(Ub,!0),!1;
+var c=!ed(a,$c(b,pd("__utmb")));a.set(bc,c);id(a,$c(b,pd("__utmz")));gd(a,$c(b,pd("__utmv")));Ed=!c;return!0},Gd=function(a){Ed||0<pd("__utmb")[w]||(X("__utmd","1",a.c(P,"/"),a.c(bb,""),a.c(Wa,""),1E4),0==pd("__utmd")[w]&&a[ta]())};var h=0,Jd=function(a){void 0==a.get(Q)?Hd(a):a.get(Ub)&&!a.get(Mc)?Hd(a):a.get(bc)&&(Id(a),h++,1<h&&H(137))},Kd=function(a){a.get(hc)&&!a.get(ac)&&(Id(a),a.set(fc,a.get($b)))},Hd=function(a){var b=a.get(ab);a.set(Sb,!0);a.set(Q,Ea()^td(a)&2147483647);a.set(Tb,"");a.set(Vb,b);a.set(Wb,b);a.set(Zb,b);a.set($b,1);a.set(ac,!0);a.set(cc,0);a.set(R,10);a.set(dc,b);a.set(Fb,[]);a.set(Ub,!1);a.set(bc,!1)},Id=function(a){a.set(Wb,a.get(Zb));a.set(Zb,a.get(ab));a.Za($b);a.set(ac,!0);a.set(cc,0);a.set(R,10);
+a.set(dc,a.get(ab));a.set(bc,!1)};var Ld="daum:q eniro:search_word naver:query pchome:q images.google:q google:q yahoo:p yahoo:q msn:q bing:q aol:query aol:q lycos:q lycos:query ask:q netscape:query cnn:query about:terms mamma:q voila:rdata virgilio:qs live:q baidu:wd alice:qs yandex:text najdi:q seznam:q rakuten:qt biglobe:q goo.ne:MT wp:szukaj onet:qt yam:k kvasir:q ozu:q terra:query rambler:query conduit:q babylon:q search-results:q avg:q comcast:q incredimail:q startsiden:q go.mail.ru:q search.centrum.cz:q 360.cn:q".split(" "),
+Sd=function(a){if(a.get(kb)&&!a.get(Mc)){for(var b=!F(a.get(ic))||!F(a.get(nc))||!F(a.get(S))||!F(a.get(lc)),c={},d=0;d<Md[w];d++){var e=Md[d];c[e]=a.get(e)}(d=a.get(rc))?(H(149),e=new Ja,Na(e,d),d=e):d=La(J[z][xa],a.get(gb)).d;if("1"!=L(d.get(a.get(ub)))||!b)if(d=Xe(a,d)||Qd(a),d||(b||!a.get(ac))||(Pd(a,void 0,"(direct)",void 0,void 0,void 0,"(direct)","(none)",void 0,void 0),d=!0),d&&(a.set(hc,Rd(a,c)),b="(direct)"==a.get(nc)&&"(direct)"==a.get(jc)&&"(none)"==a.get(oc),a.get(hc)||a.get(ac)&&!b))a.set(ec,
+a.get(ab)),a.set(fc,a.get($b)),a.Za(gc)}},Xe=function(a,b){function c(c,d){d=d||"-";var e=L(b.get(a.get(c)));return e&&"-"!=e?I(e):d}var d=L(b.get(a.get(nb)))||"-",e=L(b.get(a.get(qb)))||"-",f=L(b.get(a.get(pb)))||"-",Be=L(b.get("gclsrc"))||"-",k=L(b.get("dclid"))||"-",s=c(ob,"(not set)"),t=c(rb,"(not set)"),Za=c(sb),Ma=c(tb);if(F(d)&&F(f)&&F(k)&&F(e))return!1;var mb=!F(f)&&!F(Be),mb=F(e)&&(!F(k)||mb),Xb=F(Za);if(mb||Xb){var Bd=Nd(a),Bd=La(Bd,!0);(Bd=Od(a,Bd))&&!F(Bd[1]&&!Bd[2])&&(mb&&(e=Bd[0]),Xb&&
+(Za=Bd[1]))}Pd(a,d,e,f,Be,k,s,t,Za,Ma);return!0},Qd=function(a){var b=Nd(a),c=La(b,!0);if(!(void 0!=b&&null!=b&&""!=b&&"0"!=b&&"-"!=b&&0<=b[q]("://"))||c&&-1<c[u][q]("google")&&c.d.contains("q")&&"cse"==c[ra])return!1;if((b=Od(a,c))&&!b[2])return Pd(a,void 0,b[0],void 0,void 0,void 0,"(organic)","organic",b[1],void 0),!0;if(b||!a.get(ac))return!1;t:{for(var b=a.get(Bb),d=Ka(c[u]),e=0;e<b[w];++e)if(-1<d[q](b[e])){a=!1;break t}Pd(a,void 0,d,void 0,void 0,void 0,"(referral)","referral",void 0,"/"+c[ra]);
+a=!0}return a},Od=function(a,b){for(var c=a.get(zb),d=0;d<c[w];++d){var e=c[d][y](":");if(-1<b[u][q](e[0][D]())){var f=b.d.get(e[1]);if(f&&(f=K(f),!f&&-1<b[u][q]("google.")&&(f="(not provided)"),!e[3]||-1<b.url[q](e[3]))){t:{for(var c=f,d=a.get(Ab),c=I(c)[D](),Be=0;Be<d[w];++Be)if(c==d[Be]){c=!0;break t}c=!1}return[e[2]||e[0],f,c]}}}return null},Pd=function(a,b,c,d,e,f,Be,k,s,t){a.set(ic,b);a.set(nc,c);a.set(S,d);a.set(kc,e);a.set(lc,f);a.set(jc,Be);a.set(oc,k);a.set(pc,s);a.set(qc,t)},Md=[jc,ic,
+S,lc,nc,oc,pc,qc],Rd=function(a,b){function c(a){a=(""+a)[y]("+")[C]("%20");return a=a[y](" ")[C]("%20")}function d(c){var d=""+(a.get(c)||"");c=""+(b[c]||"");return 0<d[w]&&d==c}if(d(S)||d(lc))return H(131),!1;for(var e=0;e<Md[w];e++){var f=Md[e],Be=b[f]||"-",f=a.get(f)||"-";if(c(Be)!=c(f))return!0}return!1},Td=RegExp(/^https:\/\/(www\.)?google(\.com?)?(\.[a-z]{2}t?)?\/?$/i),Nd=function(a){a=Pa(a.get(Jb),a.get(P));try{if(Td[ia](a))return H(136),a+"?q="}catch(b){H(145)}return a};var Ud,Vd,Wd=function(a){Ud=a.c(S,"");Vd=a.c(kc,"")},Xd=function(a){var b=a.c(S,""),c=a.c(kc,"");b!=Ud&&(-1<c[q]("ds")?a.set(mc,void 0):!F(Ud)&&-1<Vd[q]("ds")&&a.set(mc,Ud))};var Zd=function(a){Yd(a,J[z][xa])?(a.set(Mc,!0),H(12)):a.set(Mc,!1)},Yd=function(a,b){if(!a.get(fb))return!1;var c=La(b,a.get(gb)),d=K(c.d.get("__utma")),e=K(c.d.get("__utmb")),f=K(c.d.get("__utmc")),Be=K(c.d.get("__utmx")),k=K(c.d.get("__utmz")),s=K(c.d.get("__utmv")),c=K(c.d.get("__utmk"));if(Yc(""+d+e+f+Be+k+s)!=c){d=I(d);e=I(e);f=I(f);Be=I(Be);f=$d(d+e+f+Be,k,s,c);if(!f)return!1;k=f[0];s=f[1]}if(!bd(a,d,!0))return!1;ed(a,e,!0);id(a,k,!0);gd(a,s,!0);ae(a,Be,!0);return!0},ce=function(a,b,c){var d;
+d=cd(a)||"-";var e=dd(a)||"-",f=""+a.b(O,1)||"-",Be=be(a)||"-",k=hd(a,!1)||"-";a=fd(a,!1)||"-";var s=Yc(""+d+e+f+Be+k+a),t=[];t[n]("__utma="+d);t[n]("__utmb="+e);t[n]("__utmc="+f);t[n]("__utmx="+Be);t[n]("__utmz="+k);t[n]("__utmv="+a);t[n]("__utmk="+s);d=t[C]("&");if(!d)return b;e=b[q]("#");if(c)return 0>e?b+"#"+d:b+"&"+d;c="";f=b[q]("?");0<e&&(c=b[B](e),b=b[B](0,e));return 0>f?b+"?"+d+c:b+"&"+d+c},$d=function(a,b,c,d){for(var e=0;3>e;e++){for(var f=0;3>f;f++){if(d==Yc(a+b+c))return H(127),[b,c];
+var Be=b[p](/ /g,"%20"),k=c[p](/ /g,"%20");if(d==Yc(a+Be+k))return H(128),[Be,k];Be=Be[p](/\+/g,"%20");k=k[p](/\+/g,"%20");if(d==Yc(a+Be+k))return H(129),[Be,k];try{var s=b[oa]("utmctr=(.*?)(?:\\|utm|$)");if(s&&2==s[w]&&(Be=b[p](s[1],G(I(s[1]))),d==Yc(a+Be+c)))return H(139),[Be,c]}catch(t){}b=I(b)}c=I(c)}};var de="|",fe=function(a,b,c,d,e,f,Be,k,s){var t=ee(a,b);t||(t={},a.get(Cb)[n](t));t.id_=b;t.affiliation_=c;t.total_=d;t.tax_=e;t.shipping_=f;t.city_=Be;t.state_=k;t.country_=s;t.items_=t.items_||[];return t},ge=function(a,b,c,d,e,f,Be){a=ee(a,b)||fe(a,b,"",0,0,0,"","","");var k;t:{if(a&&a.items_){k=a.items_;for(var s=0;s<k[w];s++)if(k[s].sku_==c){k=k[s];break t}}k=null}s=k||{};s.transId_=b;s.sku_=c;s.name_=d;s.category_=e;s.price_=f;s.quantity_=Be;k||a.items_[n](s);return s},ee=function(a,b){for(var c=
+a.get(Cb),d=0;d<c[w];d++)if(c[d].id_==b)return c[d];return null};var he,ie=function(a){if(!he){var b;b=J[z].hash;var c=W[r],d=/^#?gaso=([^&]*)/;if(c=(b=(b=b&&b[oa](d)||c&&c[oa](d))?b[1]:K(pd("GASO")))&&b[oa](/^(?:!([-0-9a-z.]{1,40})!)?([-.\w]{10,1200})$/i))Fd(a,"GASO",""+b,0),M._gasoDomain=a.get(bb),M._gasoCPath=a.get(P),a=c[1],Ia("https://www.google.com/analytics/web/inpage/pub/inpage.js?"+(a?"prefix="+a+"&":"")+Ea(),"_gasojs");he=!0}};var ae=function(a,b,c){c&&(b=I(b));c=a.b(O,1);b=b[y](".");2>b[w]||!/^\d+$/[ia](b[0])||(b[0]=""+c,Fd(a,"__utmx",b[C]("."),void 0))},be=function(a,b){var c=$c(a.get(O),pd("__utmx"));"-"==c&&(c="");return b?G(c):c},Ye=function(a){try{var b=La(J[z][xa],!1),c=ea(L(b.d.get("utm_referrer")))||"";c&&a.set(Jb,c);var d=ea(K(b.d.get("utm_expid")))||"";d&&(d=d[y](".")[0],a.set(Oc,""+d))}catch(e){H(146)}},l=function(a){var b=W.gaData&&W.gaData.expId;b&&a.set(Oc,""+b)};var ke=function(a,b){var c=m.min(a.b(Dc,0),100);if(a.b(Q,0)%100>=c)return!1;c=Ze()||$e();if(void 0==c)return!1;var d=c[0];if(void 0==d||d==ba||da(d))return!1;0<d?af(c)?b(je(c)):b(je(c[ja](0,1))):Ga(W,"load",function(){ke(a,b)},!1);return!0},me=function(a,b,c,d){var e=new yd;e.f(14,90,b[B](0,500));e.f(14,91,a[B](0,150));e.f(14,92,""+le(c));void 0!=d&&e.f(14,93,d[B](0,500));e.o(14,90,c);return e},af=function(a){for(var b=1;b<a[w];b++)if(da(a[b])||a[b]==ba||0>a[b])return!1;return!0},le=function(a){return da(a)||
+0>a?0:5E3>a?10*m[la](a/10):5E4>a?100*m[la](a/100):41E5>a?1E3*m[la](a/1E3):41E5},je=function(a){for(var b=new yd,c=0;c<a[w];c++)b.f(14,c+1,""+le(a[c])),b.o(14,c+1,a[c]);return b},Ze=function(){var a=W.performance||W.webkitPerformance;if(a=a&&a.timing){var b=a.navigationStart;if(0==b)H(133);else return[a.loadEventStart-b,a.domainLookupEnd-a.domainLookupStart,a.connectEnd-a.connectStart,a.responseStart-a.requestStart,a.responseEnd-a.responseStart,a.fetchStart-b,a.domInteractive-b,a.domContentLoadedEventStart-
+b]}},$e=function(){if(W.top==W){var a=W.external,b=a&&a.onloadT;a&&!a.isValidLoadTime&&(b=void 0);2147483648<b&&(b=void 0);0<b&&a.setPageReadyTime();return void 0==b?void 0:[b]}};var cf=function(a){if(a.get(Sb))try{var b;t:{var c=pd(a.get(Oe)||"_ga");if(c&&!(1>c[w])){for(var d=[],e=0;e<c[w];e++){var f;var Be=c[e][y]("."),k=Be.shift();if(("GA1"==k||"1"==k)&&1<Be[w]){var s=Be.shift()[y]("-");1==s[w]&&(s[1]="1");s[0]*=1;s[1]*=1;f={Ya:s,$a:Be[C](".")}}else f=void 0;f&&d[n](f)}if(1==d[w]){b=d[0].$a;break t}if(0!=d[w]){var t=a.get(Pe)||a.get(bb),d=bf(d,(0==t[q](".")?t.substr(1):t)[y](".")[w],0);if(1==d[w]){b=d[0].$a;break t}var Za=a.get(Qe)||a.get(P);(c=Za)?(1<c[w]&&"/"==c[ma](c[w]-
+1)&&(c=c.substr(0,c[w]-1)),0!=c[q]("/")&&(c="/"+c),Za=c):Za="/";d=bf(d,"/"==Za?1:Za[y]("/")[w],1);b=d[0].$a;break t}}b=void 0}if(b){var Ma=(""+b)[y](".");2==Ma[w]&&/[0-9.]/[ia](Ma)&&(H(114),a.set(Q,Ma[0]),a.set(Vb,Ma[1]),a.set(Sb,!1))}}catch(mb){H(115)}},bf=function(a,b,c){for(var d=[],e=[],f=128,Be=0;Be<a[w];Be++){var k=a[Be];if(k.Ya[c]==b)d[n](k);else if(k.Ya[c]==f)e[n](k);else k.Ya[c]<f&&(e=[k],f=k.Ya[c])}return 0<d[w]?d:e};var U=function(a,b,c){function d(a){return function(b){if((b=b.get(Nc)[a])&&b[w])for(var c=Te(e,a),d=0;d<b[w];d++)b[d].call(e,c)}}var e=this;this.a=new Zc;this.get=function(a){return this.a.get(a)};this.set=function(a,b,c){this.a.set(a,b,c)};this.set(Wa,b||"UA-XXXXX-X");this.set($a,a||"");this.set(Ya,c||"");this.set(ab,m.round((new Date)[g]()/1E3));this.set(P,"/");this.set(cb,63072E6);this.set(eb,15768E6);this.set(db,18E5);this.set(fb,!1);this.set(yb,50);this.set(gb,!1);this.set(hb,!0);this.set(ib,
+!0);this.set(jb,!0);this.set(kb,!0);this.set(lb,!0);this.set(ob,"utm_campaign");this.set(nb,"utm_id");this.set(pb,"gclid");this.set(qb,"utm_source");this.set(rb,"utm_medium");this.set(sb,"utm_term");this.set(tb,"utm_content");this.set(ub,"utm_nooverride");this.set(vb,100);this.set(Dc,1);this.set(Ec,!1);this.set(wb,"/__utm.gif");this.set(xb,1);this.set(Cb,[]);this.set(Fb,[]);this.set(zb,Ld[ja](0));this.set(Ab,[]);this.set(Bb,[]);this.B("auto");this.set(Jb,J.referrer);Ye(this.a);this.set(Nc,{hit:[],
+load:[]});this.a.g("0",Zd);this.a.g("1",Wd);this.a.g("2",Jd);this.a.g("3",cf);this.a.g("4",Sd);this.a.g("5",Xd);this.a.g("6",Kd);this.a.g("7",d("load"));this.a.g("8",ie);this.a.e("A",kd);this.a.e("B",md);this.a.e("C",Jd);this.a.e("D",jd);this.a.e("E",Tc);this.a.e("F",ne);this.a.e("G",Gd);this.a.e("H",nd);this.a.e("I",ud);this.a.e("J",Dd);this.a.e("K",l);this.a.e("L",d("hit"));this.a.e("M",oe);this.a.e("N",pe);0===this.get(ab)&&H(111);this.a.T();this.H=void 0};E=U[x];
+E.m=function(){var a=this.get(Db);a||(a=new yd,this.set(Db,a));return a};E.La=function(a){for(var b in a){var c=a[b];a.hasOwnProperty(b)&&this.set(b,c,!0)}};E.K=function(a){if(this.get(Ec))return!1;var b=this,c=ke(this.a,function(c){b.set(Hb,a,!0);b.t(c)});this.set(Ec,c);return c};E.Fa=function(a){a&&Ca(a)?(H(13),this.set(Hb,a,!0)):"object"===typeof a&&null!==a&&this.La(a);this.H=a=this.get(Hb);this.a.j("page");this.K(a)};
+E.F=function(a,b,c,d,e){if(""==a||(!wd(a)||""==b||!wd(b))||void 0!=c&&!wd(c)||void 0!=d&&!xd(d))return!1;this.set(wc,a,!0);this.set(xc,b,!0);this.set(yc,c,!0);this.set(zc,d,!0);this.set(vc,!!e,!0);this.a.j("event");return!0};E.Ha=function(a,b,c,d,e){var f=this.a.b(Dc,0);1*e===e&&(f=e);if(this.a.b(Q,0)%100>=f)return!1;c=1*(""+c);if(""==a||(!wd(a)||""==b||!wd(b)||!xd(c)||da(c)||0>c||0>f||100<f)||void 0!=d&&(""==d||!wd(d)))return!1;this.t(me(a,b,c,d));return!0};
+E.Ga=function(a,b,c,d){if(!a||!b)return!1;this.set(Ac,a,!0);this.set(Bc,b,!0);this.set(Cc,c||J[z][xa],!0);d&&this.set(Hb,d,!0);this.a.j("social");return!0};E.Ea=function(){this.set(Dc,10);this.K(this.H)};E.Ia=function(){this.a.j("trans")};E.t=function(a){this.set(Eb,a,!0);this.a.j("event")};E.ia=function(a){this.v();var b=this;return{_trackEvent:function(c,d,e){H(91);b.F(a,c,d,e)}}};E.ma=function(a){return this.get(a)};
+E.xa=function(a,b){if(a)if(Ca(a))this.set(a,b);else if("object"==typeof a)for(var c in a)a.hasOwnProperty(c)&&this.set(c,a[c])};E.addEventListener=function(a,b){var c=this.get(Nc)[a];c&&c[n](b)};E.removeEventListener=function(a,b){for(var c=this.get(Nc)[a],d=0;c&&d<c[w];d++)if(c[d]==b){c.splice(d,1);break}};E.qa=function(){return"5.4.3"};E.B=function(a){this.get(hb);a="auto"==a?Ka(J.domain):a&&"-"!=a&&"none"!=a?a[D]():"";this.set(bb,a)};E.va=function(a){this.set(hb,!!a)};
+E.na=function(a,b){return ce(this.a,a,b)};E.link=function(a,b){if(this.a.get(fb)&&a){var c=ce(this.a,a,b);J[z].href=c}};E.ua=function(a,b){this.a.get(fb)&&(a&&a.action)&&(a.action=ce(this.a,a.action,b))};
+E.za=function(){this.v();var a=this.a,b=J.getElementById?J.getElementById("utmtrans"):J.utmform&&J.utmform.utmtrans?J.utmform.utmtrans:null;if(b&&b[na]){a.set(Cb,[]);for(var b=b[na][y]("UTM:"),c=0;c<b[w];c++){b[c]=Da(b[c]);for(var d=b[c][y](de),e=0;e<d[w];e++)d[e]=Da(d[e]);"T"==d[0]?fe(a,d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8]):"I"==d[0]&&ge(a,d[1],d[2],d[3],d[4],d[5],d[6])}}};E.$=function(a,b,c,d,e,f,Be,k){return fe(this.a,a,b,c,d,e,f,Be,k)};E.Y=function(a,b,c,d,e,f){return ge(this.a,a,b,c,d,e,f)};
+E.Aa=function(a){de=a||"|"};E.ea=function(){this.set(Cb,[])};E.wa=function(a,b,c,d){var e=this.a;if(0>=a||a>e.get(yb))a=!1;else if(!b||!c||128<b[w]+c[w])a=!1;else{1!=d&&2!=d&&(d=3);var f={};ha(f,b);f.value=c;f.scope=d;e.get(Fb)[a]=f;a=!0}a&&this.a.n();return a};E.ka=function(a){this.a.get(Fb)[a]=void 0;this.a.n()};E.ra=function(a){return(a=this.a.get(Fb)[a])&&1==a[ua]?a[na]:void 0};E.Ca=function(a,b,c){this.m().f(a,b,c)};E.Da=function(a,b,c){this.m().o(a,b,c)};
+E.sa=function(a,b){return this.m().getKey(a,b)};E.ta=function(a,b){return this.m().N(a,b)};E.fa=function(a){this.m().L(a)};E.ga=function(a){this.m().M(a)};E.ja=function(){return new yd};E.W=function(a){a&&this.get(Ab)[n](a[D]())};E.ba=function(){this.set(Ab,[])};E.X=function(a){a&&this.get(Bb)[n](a[D]())};E.ca=function(){this.set(Bb,[])};E.Z=function(a,b,c,d,e){if(a&&b){a=[a,b[D]()][C](":");if(d||e)a=[a,d,e][C](":");d=this.get(zb);d.splice(c?0:d[w],0,a)}};E.da=function(){this.set(zb,[])};
+E.ha=function(a){this.a[ka]();var b=this.get(P),c=be(this.a);this.set(P,a);this.a.n();ae(this.a,c);this.set(P,b)};E.ya=function(a,b){if(0<a&&5>=a&&Ca(b)&&""!=b){var c=this.get(Fc)||[];c[a]=b;this.set(Fc,c)}};E.V=function(a){a=""+a;if(a[oa](/^[A-Za-z0-9]{1,5}$/)){var b=this.get(Ic)||[];b[n](a);this.set(Ic,b)}};E.v=function(){this.a[ka]()};E.Ba=function(a){a&&""!=a&&(this.set(Tb,a),this.a.j("var"))};var ne=function(a){"trans"!==a.get(sc)&&500<=a.b(cc,0)&&a[ta]();if("event"===a.get(sc)){var b=(new Date)[g](),c=a.b(dc,0),d=a.b(Zb,0),c=m[la](1*((b-(c!=d?c:1E3*c))/1E3));0<c&&(a.set(dc,b),a.set(R,m.min(10,a.b(R,0)+c)));0>=a.b(R,0)&&a[ta]()}},pe=function(a){"event"===a.get(sc)&&a.set(R,m.max(0,a.b(R,10)-1))};var qe=function(){var a=[];this.add=function(b,c,d){d&&(c=G(""+c));a[n](b+"="+c)};this.toString=function(){return a[C]("&")}},re=function(a,b){(b||2!=a.get(xb))&&a.Za(cc)},se=function(a,b){b.add("utmwv","5.4.3");b.add("utms",a.get(cc));b.add("utmn",Ea());var c=J[z].hostname;F(c)||b.add("utmhn",c,!0);c=a.get(vb);100!=c&&b.add("utmsp",c,!0)},te=function(a,b){b.add("utmht",(new Date)[g]());b.add("utmac",Da(a.get(Wa)));a.get(Oc)&&b.add("utmxkey",a.get(Oc),!0);a.get(vc)&&b.add("utmni",1);var c=a.get(Ic);
+c&&0<c[w]&&b.add("utmdid",c[C]("."));ff(a,b);!1!==a.get(Xa)&&(a.get(Xa)||M.w)&&b.add("aip",1);b.add("utmu",od.Xa())},ue=function(a,b){for(var c=a.get(Fc)||[],d=[],e=1;e<c[w];e++)c[e]&&d[n](e+":"+G(c[e][p](/%/g,"%25")[p](/:/g,"%3A")[p](/,/g,"%2C")));d[w]&&b.add("utmpg",d[C](","))},ff=function(a,b){function c(a,b){b&&d[n](a+"="+b+";")}var d=[];c("__utma",cd(a));c("__utmz",hd(a,!1));c("__utmv",fd(a,!0));c("__utmx",be(a));b.add("utmcc",d[C]("+"),!0)},ve=function(a,b){a.get(ib)&&(b.add("utmcs",a.get(Qb),
+!0),b.add("utmsr",a.get(Lb)),a.get(Rb)&&b.add("utmvp",a.get(Rb)),b.add("utmsc",a.get(Mb)),b.add("utmul",a.get(Pb)),b.add("utmje",a.get(Nb)),b.add("utmfl",a.get(Ob),!0))},we=function(a,b){a.get(lb)&&a.get(Ib)&&b.add("utmdt",a.get(Ib),!0);b.add("utmhid",a.get(Kb));b.add("utmr",Pa(a.get(Jb),a.get(P)),!0);b.add("utmp",G(a.get(Hb),!0),!0)},xe=function(a,b){for(var c=a.get(Db),d=a.get(Eb),e=a.get(Fb)||[],f=0;f<e[w];f++){var Be=e[f];Be&&(c||(c=new yd),c.f(8,f,Be[r]),c.f(9,f,Be[na]),3!=Be[ua]&&c.f(11,f,""+
+Be[ua]))}F(a.get(wc))||F(a.get(xc),!0)||(c||(c=new yd),c.f(5,1,a.get(wc)),c.f(5,2,a.get(xc)),e=a.get(yc),void 0!=e&&c.f(5,3,e),e=a.get(zc),void 0!=e&&c.o(5,1,e));c?b.add("utme",c.Qa(d),!0):d&&b.add("utme",d.A(),!0)},ye=function(a,b,c){var d=new qe;re(a,c);se(a,d);d.add("utmt","tran");d.add("utmtid",b.id_,!0);d.add("utmtst",b.affiliation_,!0);d.add("utmtto",b.total_,!0);d.add("utmttx",b.tax_,!0);d.add("utmtsp",b.shipping_,!0);d.add("utmtci",b.city_,!0);d.add("utmtrg",b.state_,!0);d.add("utmtco",b.country_,
+!0);xe(a,d);ve(a,d);we(a,d);(b=a.get(Gb))&&d.add("utmcu",b,!0);c||(ue(a,d),te(a,d));return d[v]()},ze=function(a,b,c){var d=new qe;re(a,c);se(a,d);d.add("utmt","item");d.add("utmtid",b.transId_,!0);d.add("utmipc",b.sku_,!0);d.add("utmipn",b.name_,!0);d.add("utmiva",b.category_,!0);d.add("utmipr",b.price_,!0);d.add("utmiqt",b.quantity_,!0);xe(a,d);ve(a,d);we(a,d);(b=a.get(Gb))&&d.add("utmcu",b,!0);c||(ue(a,d),te(a,d));return d[v]()},Ae=function(a,b){var c=a.get(sc);if("page"==c)c=new qe,re(a,b),se(a,
+c),xe(a,c),ve(a,c),we(a,c),b||(ue(a,c),te(a,c)),c=[c[v]()];else if("event"==c)c=new qe,re(a,b),se(a,c),c.add("utmt","event"),xe(a,c),ve(a,c),we(a,c),b||(ue(a,c),te(a,c)),c=[c[v]()];else if("var"==c)c=new qe,re(a,b),se(a,c),c.add("utmt","var"),!b&&te(a,c),c=[c[v]()];else if("trans"==c)for(var c=[],d=a.get(Cb),e=0;e<d[w];++e){c[n](ye(a,d[e],b));for(var f=d[e].items_,Be=0;Be<f[w];++Be)c[n](ze(a,f[Be],b))}else"social"==c?b?c=[]:(c=new qe,re(a,b),se(a,c),c.add("utmt","social"),c.add("utmsn",a.get(Ac),
+!0),c.add("utmsa",a.get(Bc),!0),c.add("utmsid",a.get(Cc),!0),xe(a,c),ve(a,c),we(a,c),ue(a,c),te(a,c),c=[c[v]()]):"feedback"==c?b?c=[]:(c=new qe,re(a,b),se(a,c),c.add("utmt","feedback"),c.add("utmfbid",a.get(Gc),!0),c.add("utmfbpr",a.get(Hc),!0),xe(a,c),ve(a,c),we(a,c),ue(a,c),te(a,c),c=[c[v]()]):c=[];return c},oe=function(a){var b,c=a.get(xb),d=a.get(uc),e=d&&d.Ua,f=0;if(0==c||2==c){var Be=a.get(wb)+"?";b=Ae(a,!0);for(var k=0,s=b[w];k<s;k++)Sa(b[k],e,Be,!0),f++}if(1==c||2==c)for(b=Ae(a),k=0,s=b[w];k<
+s;k++)try{Sa(b[k],e),f++}catch(t){t&&Ra(t[r],void 0,t.message)}d&&(d.q=f)};var Ce=function(a){ha(this,"len");this.message=a+"-8192"},De=function(a){ha(this,"ff2post");this.message=a+"-2036"},Sa=function(a,b,c,d){b=b||Fa;if(d||2036>=a[w])gf(a,b,c);else if(8192>=a[w]){if(0<=W[za].userAgent[q]("Firefox")&&![].reduce)throw new De(a[w]);hf(a,b)||Ee(a,b)}else throw new Ce(a[w]);},gf=function(a,b,c){c=c||("https:"==J[z][A]||M.G?"https://ssl.google-analytics.com":"http://www.google-analytics.com")+"/__utm.gif?";var d=new Image(1,1);d.src=c+a;d.onload=function(){d.onload=null;d.onerror=
+null;b()};d.onerror=function(){d.onload=null;d.onerror=null;b()}},hf=function(a,b){var c,d=("https:"==J[z][A]||M.G?"https://ssl.google-analytics.com":"http://www.google-analytics.com")+"/p/__utm.gif",e=W.XDomainRequest;if(e)c=new e,c.open("POST",d);else if(e=W.XMLHttpRequest)e=new e,"withCredentials"in e&&(c=e,c.open("POST",d,!0),c.setRequestHeader("Content-Type","text/plain"));if(c)return c.onreadystatechange=function(){4==c.readyState&&(b(),c=null)},c.send(a),!0},Ee=function(a,b){if(J.body){a=aa(a);
+try{var c=J[qa]('<iframe name="'+a+'"></iframe>')}catch(d){c=J[qa]("iframe"),ha(c,a)}c.height="0";c.width="0";c.style.display="none";c.style.visibility="hidden";var e=J[z],e=("https:"==J[z][A]||M.G?"https://ssl.google-analytics.com":"http://www.google-analytics.com")+"/u/post_iframe.html#"+aa(e[A]+"//"+e[u]+"/favicon.ico"),f=function(){c.src="";c.parentNode&&c.parentNode.removeChild(c)};Ga(W,"beforeunload",f);var Be=!1,k=0,s=function(){if(!Be){try{if(9<k||c.contentWindow[z][u]==J[z][u]){Be=!0;f();
+Ha(W,"beforeunload",f);b();return}}catch(a){}k++;ca(s,200)}};Ga(c,"load",s);J.body.appendChild(c);c.src=e}else We(function(){Ee(a,b)},100)};var $=function(){this.G=this.w=!1;this.C={};this.D=[];this.U=0;this.S=[["www.google-analytics.com","","/plugins/"]];this._gasoCPath=this._gasoDomain=void 0;Re();Se()};E=$[x];E.oa=function(a,b){return this.r(a,void 0,b)};E.r=function(a,b,c){b&&H(23);c&&H(67);void 0==b&&(b="~"+M.U++);a=new U(b,a,c);M.C[b]=a;M.D[n](a);return a};E.u=function(a){a=a||"";return M.C[a]||M.r(void 0,a)};E.pa=function(){return M.D[ja](0)};E.aa=function(){this.w=!0};E.la=function(){this.G=!0};var Fe=function(a){if("prerender"==J.webkitVisibilityState)return!1;a();return!0};var M=new $;var jf=W._gat;jf&&Ba(jf._getTracker)?M=jf:W._gat=M;var Z=new Y;(function(a){if(!Fe(a)){H(123);var b=!1,c=function(){!b&&Fe(a)&&(b=!0,Ha(J,"webkitvisibilitychange",c))};Ga(J,"webkitvisibilitychange",c)}})(function(){var a=W._gaq,b=!1;if(a&&Ba(a[n])&&(b="[object Array]"==Object[x][v].call(Object(a)),!b)){Z=a;return}W._gaq=Z;b&&Z[n][ya](Z,a)});function Yc(a){var b=1,c=0,d;if(a)for(b=0,d=a[w]-1;0<=d;d--)c=a.charCodeAt(d),b=(b<<6&268435455)+c+(c<<14),c=b&266338304,b=0!=c?b^c>>21:b;return b};})();
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/highlight.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/highlight.js
new file mode 100644
index 0000000..6808403
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/highlight.js
@@ -0,0 +1,2 @@
+var hljs=new function(){var m={};var b={};function n(q){return q.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function f(s,r){if(!s){return false}for(var q=0;q<s.length;q++){if(s[q]==r){return true}}return false}function e(C,E){function D(O,P){O.sub_modes=[];for(var N=0;N<O.contains.length;N++){for(var M=0;M<P.modes.length;M++){if(P.modes[M].className==O.contains[N]){O.sub_modes[O.sub_modes.length]=P.modes[M]}}}}function s(M,O){if(!O.contains){return null}if(!O.sub_modes){D(O,F)}for(var N=0;N<O.sub_modes.length;N++){if(O.sub_modes[N].beginRe.test(M)){return O.sub_modes[N]}}return null}function x(N,M){if(q[N].end&&q[N].endRe.test(M)){return 1}if(q[N].endsWithParent){var O=x(N-1,M);return O?O+1:0}return 0}function y(M,N){return N.illegalRe&&N.illegalRe.test(M)}function L(R,S){var N=[];function Q(T){if(!f(N,T)){N[N.length]=T}}if(R.contains){for(var P=0;P<S.modes.length;P++){if(f(R.contains,S.modes[P].className)){Q(S.modes[P].begin)}}}var O=q.length-1;do{if(q[O].end){Q(q[O].end)}O--}while(q[O+1].endsWithParent);if(R.illegal){Q(R.illegal)}var M="("+N[0];for(var P=0;P<N.length;P++){M+="|"+N[P]}M+=")";return h(S,M)}function r(O,N){var P=q[q.length-1];if(!P.terminators){P.terminators=L(P,F)}O=O.substr(N);var M=P.terminators.exec(O);if(!M){return[O,"",true]}if(M.index==0){return["",M[0],false]}else{return[O.substr(0,M.index),M[0],false]}}function B(Q,M){var O=F.case_insensitive?M[0].toLowerCase():M[0];for(var N in Q.keywordGroups){if(!Q.keywordGroups.hasOwnProperty(N)){continue}var P=Q.keywordGroups[N].hasOwnProperty(O);if(P){return[N,P]}}return false}function G(N,T){if(!T.keywords||!T.lexems){return n(N)}if(!T.lexemsRe){var S="("+T.lexems[0];for(var P=1;P<T.lexems.length;P++){S+="|"+T.lexems[P]}S+=")";T.lexemsRe=h(F,S,true)}var M="";var R=0;T.lexemsRe.lastIndex=0;var O=T.lexemsRe.exec(N);while(O){M+=n(N.substr(R,O.index-R));var Q=B(T,O);if(Q){z+=Q[1];M+='<span class="'+Q[0]+'">'+n(O[0])+"</span>"}else{M+=n(O[0])}R=T.lexemsRe.lastIndex;O=T.lexemsRe.exec(N)}M+=n(N.substr(R,N.length-R));return M}function K(N,O){if(O.subLanguage&&b[O.subLanguage]){var M=e(O.subLanguage,N);z+=M.keyword_count;v+=M.relevance;return M.value}else{return G(N,O)}}function J(O,M){var N=O.noMarkup?"":'<span class="'+O.className+'">';if(O.returnBegin){A+=N;O.buffer=""}else{if(O.excludeBegin){A+=n(M)+N;O.buffer=""}else{A+=N;O.buffer=M}}q[q.length]=O}function H(P,O,N){var T=q[q.length-1];if(N){A+=K(T.buffer+P,T);return false}var R=s(O,T);if(R){A+=K(T.buffer+P,T);J(R,O);v+=R.relevance;return R.returnBegin}var M=x(q.length-1,O);if(M){var Q=T.noMarkup?"":"</span>";if(T.returnEnd){A+=K(T.buffer+P,T)+Q}else{if(T.excludeEnd){A+=K(T.buffer+P,T)+Q+n(O)}else{A+=K(T.buffer+P+O,T)+Q}}while(M>1){Q=q[q.length-2].noMarkup?"":"</span>";A+=Q;M--;q.length--}q.length--;q[q.length-1].buffer="";if(T.starts){for(var S=0;S<F.modes.length;S++){if(F.modes[S].className==T.starts){J(F.modes[S],"");break}}}return T.returnEnd}if(y(O,T)){throw"Illegal"}}var F=m[C];var q=[F.defaultMode];var v=0;var z=0;var A="";try{var w=0;F.defaultMode.buffer="";do{var t=r(E,w);var u=H(t[0],t[1],t[2]);w+=t[0].length;if(!u){w+=t[1].length}}while(!t[2]);if(q.length>1){throw"Illegal"}return{relevance:v,keyword_count:z,value:A}}catch(I){if(I=="Illegal"){return{relevance:0,keyword_count:0,value:n(E)}}else{throw I}}}function i(s){var q="";for(var r=0;r<s.childNodes.length;r++){if(s.childNodes[r].nodeType==3){q+=s.childNodes[r].nodeValue}else{if(s.childNodes[r].nodeName=="BR"){q+="\n"}else{q+=i(s.childNodes[r])}}}return q}function a(t){var s=t.className.split(/\s+/);s=s.concat(t.parentNode.className.split(/\s+/));for(var r=0;r<s.length;r++){var q=s[r].replace(/^language-/,"");if(q=="no-highlight"){throw"No highlight"}if(m[q]){return q}}}function d(r){var q=[];(function(t,u){for(var s=0;s<t.childNodes.length;s++){if(t.childNodes[s].nodeType==3){u+=t.childNodes[s].nodeValue.length}else{if(t.childNodes[s].nodeName=="BR"){u+=1}else{q.push({event:"start",offset:u,node:t.childNodes[s]});u=arguments.callee(t.childNodes[s],u);q.push({event:"stop",offset:u,node:t.childNodes[s]})}}}return u})(r,0);return q}function k(z,x,y){var r=0;var B="";var t=[];function v(){if(z.length&&x.length){if(z[0].offset!=x[0].offset){return(z[0].offset<x[0].offset)?z:x}else{return(z[0].event=="start"&&x[0].event=="stop")?x:z}}else{return z.length?z:x}}function u(E){var C="<"+E.nodeName.toLowerCase();for(var D=0;D<E.attributes.length;D++){C+=" "+E.attributes[D].nodeName.toLowerCase()+'="'+n(E.attributes[D].nodeValue)+'"'}return C+">"}function A(C){return"</"+C.nodeName.toLowerCase()+">"}while(z.length||x.length){var w=v().splice(0,1)[0];B+=n(y.substr(r,w.offset-r));r=w.offset;if(w.event=="start"){B+=u(w.node);t.push(w.node)}else{if(w.event=="stop"){var s=t.length;do{s--;var q=t[s];B+=A(q)}while(q!=w.node);t.splice(s,1);while(s<t.length){B+=u(t[s]);s++}}}}B+=y.substr(r);return B}function o(u,A){try{var C=i(u);var y=a(u)}catch(z){if(z=="No highlight"){return}}if(y){var E=e(y,C).value}else{var D=0;for(var B in b){if(!b.hasOwnProperty(B)){continue}var s=e(B,C);var x=s.keyword_count+s.relevance;if(x>D){D=x;var E=s.value;y=B}}}if(E){if(A){E=E.replace(/^(\t+)/gm,function(F,I,H,G){return I.replace(/\t/g,A)})}var w=u.className;if(!w.match(y)){w+=" "+y}var r=d(u);if(r.length){var t=document.createElement("pre");t.innerHTML=E;E=k(r,d(t),C)}var q=document.createElement("div");q.innerHTML='<pre><code class="'+w+'">'+E+"</code></pre>";var v=u.parentNode.parentNode;v.replaceChild(q.firstChild,u.parentNode)}}function h(t,r,q){var s="m"+(t.case_insensitive?"i":"")+(q?"g":"");return new RegExp(r,s)}function j(){for(var r in m){if(!m.hasOwnProperty(r)){continue}var s=m[r];for(var q=0;q<s.modes.length;q++){if(s.modes[q].begin){s.modes[q].beginRe=h(s,"^"+s.modes[q].begin)}if(s.modes[q].end){s.modes[q].endRe=h(s,"^"+s.modes[q].end)}if(s.modes[q].illegal){s.modes[q].illegalRe=h(s,"^(?:"+s.modes[q].illegal+")")}s.defaultMode.illegalRe=h(s,"^(?:"+s.defaultMode.illegal+")");if(s.modes[q].relevance==undefined){s.modes[q].relevance=1}}}}function g(){function q(v){if(!v.keywordGroups){for(var u in v.keywords){if(!v.keywords.hasOwnProperty(u)){continue}if(v.keywords[u] instanceof Object){v.keywordGroups=v.keywords}else{v.keywordGroups={keyword:v.keywords}}break}}}for(var s in m){if(!m.hasOwnProperty(s)){continue}var t=m[s];q(t.defaultMode);for(var r=0;r<t.modes.length;r++){q(t.modes[r])}}}function c(r){for(var q=0;q<r.childNodes.length;q++){node=r.childNodes[q];if(node.nodeName=="CODE"){return node}if(!(node.nodeType==3&&node.nodeValue.match(/\s+/))){return null}}}function p(){if(p.called){return}p.called=true;j();g();if(arguments.length){for(var q=0;q<arguments.length;q++){if(m[arguments[q]]){b[arguments[q]]=m[arguments[q]]}}}else{b=m}var s=document.getElementsByTagName("pre");for(var q=0;q<s.length;q++){var r=c(s[q]);if(r){o(r,hljs.tabReplace)}}}function l(){var q=arguments;var r=function(){p.apply(null,q)};if(window.addEventListener){window.addEventListener("DOMContentLoaded",r,false);window.addEventListener("load",r,false)}else{if(window.attachEvent){window.attachEvent("onload",r)}else{window.onload=r}}}this.LANGUAGES=m;this.initHighlightingOnLoad=l;this.highlightBlock=o;this.initHighlighting=p;this.IDENT_RE="[a-zA-Z][a-zA-Z0-9_]*";this.UNDERSCORE_IDENT_RE="[a-zA-Z_][a-zA-Z0-9_]*";this.NUMBER_RE="\\b\\d+(\\.\\d+)?";this.C_NUMBER_RE="\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)";this.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.APOS_STRING_MODE={className:"string",begin:"'",end:"'",illegal:"\\n",contains:["escape"],relevance:0};this.QUOTE_STRING_MODE={className:"string",begin:'"',end:'"',illegal:"\\n",contains:["escape"],relevance:0};this.BACKSLASH_ESCAPE={className:"escape",begin:"\\\\.",end:"^",noMarkup:true,relevance:0};this.C_LINE_COMMENT_MODE={className:"comment",begin:"//",end:"$",relevance:0};this.C_BLOCK_COMMENT_MODE={className:"comment",begin:"/\\*",end:"\\*/"};this.HASH_COMMENT_MODE={className:"comment",begin:"#",end:"$"};this.C_NUMBER_MODE={className:"number",begin:this.C_NUMBER_RE,end:"^",relevance:0}}();var initHighlightingOnLoad=hljs.initHighlightingOnLoad;hljs.LANGUAGES.bash=function(){var a={"true":1,"false":1};return{defaultMode:{lexems:[hljs.IDENT_RE],contains:["string","shebang","comment","number","test_condition","string","variable"],keywords:{keyword:{"if":1,then:1,"else":1,fi:1,"for":1,"break":1,"continue":1,"while":1,"in":1,"do":1,done:1,echo:1,exit:1,"return":1,set:1,declare:1},literal:a}},case_insensitive:false,modes:[{className:"shebang",begin:"(#!\\/bin\\/bash)|(#!\\/bin\\/sh)",end:"^",relevance:10},hljs.HASH_COMMENT_MODE,{className:"test_condition",begin:"\\[ ",end:" \\]",contains:["string","variable","number"],lexems:[hljs.IDENT_RE],keywords:{literal:a},relevance:0},{className:"test_condition",begin:"\\[\\[ ",end:" \\]\\]",contains:["string","variable","number"],lexems:[hljs.IDENT_RE],keywords:{literal:a}},{className:"variable",begin:"\\$([a-zA-Z0-9_]+)\\b",end:"^"},{className:"variable",begin:"\\$\\{(([^}])|(\\\\}))+\\}",end:"^",contains:["number"]},{className:"string",begin:'"',end:'"',illegal:"\\n",contains:["escape","variable"],relevance:0},{className:"string",begin:'"',end:'"',illegal:"\\n",contains:["escape","variable"],relevance:0},hljs.BACKSLASH_ESCAPE,hljs.C_NUMBER_MODE,{className:"comment",begin:"\\/\\/",end:"$",illegal:"."}]}}();hljs.LANGUAGES.cpp=function(){var a={keyword:{"false":1,"int":1,"float":1,"while":1,"private":1,"char":1,"catch":1,"export":1,virtual:1,operator:2,sizeof:2,dynamic_cast:2,typedef:2,const_cast:2,"const":1,struct:1,"for":1,static_cast:2,union:1,namespace:1,unsigned:1,"long":1,"throw":1,"volatile":2,"static":1,"protected":1,bool:1,template:1,mutable:1,"if":1,"public":1,friend:2,"do":1,"return":1,"goto":1,auto:1,"void":2,"enum":1,"else":1,"break":1,"new":1,extern:1,using:1,"true":1,"class":1,asm:1,"case":1,typeid:1,"short":1,reinterpret_cast:2,"default":1,"double":1,register:1,explicit:1,signed:1,typename:1,"try":1,"this":1,"switch":1,"continue":1,wchar_t:1,inline:1,"delete":1},built_in:{std:1,string:1,cin:1,cout:1,cerr:1,clog:1,stringstream:1,istringstream:1,ostringstream:1,auto_ptr:1,deque:1,list:1,queue:1,stack:1,vector:1,map:1,set:1,bitset:1,multiset:1,multimap:1}};return{defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],illegal:"</",contains:["comment","string","number","preprocessor","stl_container"],keywords:a},modes:[hljs.C_LINE_COMMENT_MODE,hljs.C_BLOCK_COMMENT_MODE,hljs.C_NUMBER_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,{className:"string",begin:"'",end:"[^\\\\]'",illegal:"[^\\\\][^']"},{className:"preprocessor",begin:"#",end:"$"},{className:"stl_container",begin:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap)\\s*<",end:">",contains:["stl_container"],lexems:[hljs.UNDERSCORE_IDENT_RE],keywords:a,relevance:10}]}}();hljs.LANGUAGES.cs={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["comment","string","number"],keywords:{"abstract":1,as:1,base:1,bool:1,"break":1,"byte":1,"case":1,"catch":1,"char":1,checked:1,"class":1,"const":1,"continue":1,decimal:1,"default":1,delegate:1,"do":1,"do":1,"double":1,"else":1,"enum":1,event:1,explicit:1,extern:1,"false":1,"finally":1,fixed:1,"float":1,"for":1,foreach:1,"goto":1,"if":1,implicit:1,"in":1,"int":1,"interface":1,internal:1,is:1,lock:1,"long":1,namespace:1,"new":1,"null":1,object:1,operator:1,out:1,override:1,params:1,"private":1,"protected":1,"public":1,readonly:1,ref:1,"return":1,sbyte:1,sealed:1,"short":1,sizeof:1,stackalloc:1,"static":1,string:1,struct:1,"switch":1,"this":1,"throw":1,"true":1,"try":1,"typeof":1,uint:1,ulong:1,unchecked:1,unsafe:1,ushort:1,using:1,virtual:1,"volatile":1,"void":1,"while":1,ascending:1,descending:1,from:1,get:1,group:1,into:1,join:1,let:1,orderby:1,partial:1,select:1,set:1,value:1,"var":1,where:1,yield:1}},modes:[{className:"comment",begin:"///",end:"$",returnBegin:true,contains:["xmlDocTag"]},{className:"xmlDocTag",begin:"///|<!--|-->",end:"^"},{className:"xmlDocTag",begin:"</?",end:">"},{className:"string",begin:'@"',end:'"',contains:["quoteQuote"]},{className:"quoteQuote",begin:'""',end:"^"},hljs.C_LINE_COMMENT_MODE,hljs.C_BLOCK_COMMENT_MODE,hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,hljs.C_NUMBER_MODE]};hljs.LANGUAGES.css={defaultMode:{contains:["at_rule","id","class","attr_selector","pseudo","rules","comment"],keywords:hljs.HTML_TAGS,lexems:[hljs.IDENT_RE],illegal:"="},case_insensitive:true,modes:[{className:"at_rule",begin:"@",end:"[{;]",excludeEnd:true,lexems:[hljs.IDENT_RE],keywords:{"import":1,page:1,media:1,charset:1,"font-face":1},contains:["function","string","number","pseudo"]},{className:"id",begin:"\\#[A-Za-z0-9_-]+",end:"^"},{className:"class",begin:"\\.[A-Za-z0-9_-]+",end:"^",relevance:0},{className:"attr_selector",begin:"\\[",end:"\\]",illegal:"$"},{className:"pseudo",begin:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+",end:"^"},{className:"rules",begin:"{",end:"}",contains:["rule","comment"],illegal:"[^\\s]"},{className:"rule",begin:"[A-Z\\_\\.\\-]+\\s*:",end:";",endsWithParent:true,lexems:["[A-Za-z-]+"],keywords:{"play-during":1,"counter-reset":1,"counter-increment":1,"min-height":1,quotes:1,"border-top":1,pitch:1,font:1,pause:1,"list-style-image":1,"border-width":1,cue:1,"outline-width":1,"border-left":1,elevation:1,richness:1,"speech-rate":1,"border-bottom":1,"border-spacing":1,background:1,"list-style-type":1,"text-align":1,"page-break-inside":1,orphans:1,"page-break-before":1,"text-transform":1,"line-height":1,"padding-left":1,"font-size":1,right:1,"word-spacing":1,"padding-top":1,"outline-style":1,bottom:1,content:1,"border-right-style":1,"padding-right":1,"border-left-style":1,"voice-family":1,"background-color":1,"border-bottom-color":1,"outline-color":1,"unicode-bidi":1,"max-width":1,"font-family":1,"caption-side":1,"border-right-width":1,"pause-before":1,"border-top-style":1,color:1,"border-collapse":1,"border-bottom-width":1,"float":1,height:1,"max-height":1,"margin-right":1,"border-top-width":1,speak:1,"speak-header":1,top:1,"cue-before":1,"min-width":1,width:1,"font-variant":1,"border-top-color":1,"background-position":1,"empty-cells":1,direction:1,"border-right":1,visibility:1,padding:1,"border-style":1,"background-attachment":1,overflow:1,"border-bottom-style":1,cursor:1,margin:1,display:1,"border-left-width":1,"letter-spacing":1,"vertical-align":1,clip:1,"border-color":1,"list-style":1,"padding-bottom":1,"pause-after":1,"speak-numeral":1,"margin-left":1,widows:1,border:1,"font-style":1,"border-left-color":1,"pitch-range":1,"background-repeat":1,"table-layout":1,"margin-bottom":1,"speak-punctuation":1,"font-weight":1,"border-right-color":1,"page-break-after":1,position:1,"white-space":1,"text-indent":1,"background-image":1,volume:1,stress:1,outline:1,clear:1,"z-index":1,"text-decoration":1,"margin-top":1,azimuth:1,"cue-after":1,left:1,"list-style-position":1},contains:["value"]},hljs.C_BLOCK_COMMENT_MODE,{className:"value",begin:"^",endsWithParent:true,excludeEnd:true,contains:["function","number","hexcolor","string"]},{className:"number",begin:hljs.NUMBER_RE,end:"^"},{className:"hexcolor",begin:"\\#[0-9A-F]+",end:"^"},{className:"function",begin:hljs.IDENT_RE+"\\(",end:"\\)",contains:["params"]},{className:"params",begin:"^",endsWithParent:true,excludeEnd:true,contains:["number","string"]},hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE]};hljs.LANGUAGES.diff={case_insensitive:true,defaultMode:{contains:["chunk","header","addition","deletion","change"]},modes:[{className:"chunk",begin:"^\\@\\@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +\\@\\@$",end:"^",relevance:10},{className:"chunk",begin:"^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$",end:"^",relevance:10},{className:"chunk",begin:"^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$",end:"^",relevance:10},{className:"header",begin:"Index: ",end:"$"},{className:"header",begin:"=====",end:"=====$"},{className:"header",begin:"^\\-\\-\\-",end:"$"},{className:"header",begin:"^\\*{3} ",end:"$"},{className:"header",begin:"^\\+\\+\\+",end:"$"},{className:"header",begin:"\\*{5}",end:"\\*{5}$"},{className:"addition",begin:"^\\+",end:"$"},{className:"deletion",begin:"^\\-",end:"$"},{className:"change",begin:"^\\!",end:"$"}]};hljs.XML_COMMENT={className:"comment",begin:"<!--",end:"-->"};hljs.XML_ATTR={className:"attribute",begin:"\\s[a-zA-Z\\:_-]+=",end:"^",contains:["value"]};hljs.XML_VALUE_QUOT={className:"value",begin:'"',end:'"'};hljs.XML_VALUE_APOS={className:"value",begin:"'",end:"'"};hljs.LANGUAGES.xml={defaultMode:{contains:["pi","comment","cdata","tag"]},case_insensitive:true,modes:[{className:"pi",begin:"<\\?",end:"\\?>",relevance:10},hljs.XML_COMMENT,{className:"cdata",begin:"<\\!\\[CDATA\\[",end:"\\]\\]>"},{className:"tag",begin:"</?",end:">",contains:["title","tag_internal"],relevance:1.5},{className:"title",begin:"[A-Za-z:_][A-Za-z0-9\\._:-]+",end:"^",relevance:0},{className:"tag_internal",begin:"^",endsWithParent:true,noMarkup:true,contains:["attribute"],relevance:0,illegal:"[\\+\\.]"},hljs.XML_ATTR,hljs.XML_VALUE_QUOT,hljs.XML_VALUE_APOS]};hljs.HTML_TAGS={code:1,kbd:1,font:1,noscript:1,style:1,img:1,title:1,menu:1,tt:1,tr:1,param:1,li:1,tfoot:1,th:1,input:1,td:1,dl:1,blockquote:1,fieldset:1,big:1,dd:1,abbr:1,optgroup:1,dt:1,button:1,isindex:1,p:1,small:1,div:1,dir:1,em:1,frame:1,meta:1,sub:1,bdo:1,label:1,acronym:1,sup:1,body:1,xml:1,basefont:1,base:1,br:1,address:1,strong:1,legend:1,ol:1,script:1,caption:1,s:1,col:1,h2:1,h3:1,h1:1,h6:1,h4:1,h5:1,table:1,select:1,noframes:1,span:1,area:1,dfn:1,strike:1,cite:1,thead:1,head:1,option:1,form:1,hr:1,"var":1,link:1,b:1,colgroup:1,ul:1,applet:1,del:1,iframe:1,pre:1,frameset:1,ins:1,tbody:1,html:1,samp:1,map:1,object:1,a:1,xmlns:1,center:1,textarea:1,i:1,q:1,u:1};hljs.HTML_DOCTYPE={className:"doctype",begin:"<!DOCTYPE",end:">",relevance:10};hljs.HTML_ATTR={className:"attribute",begin:"\\s[a-zA-Z\\:_-]+=",end:"^",contains:["value"]};hljs.HTML_SHORT_ATTR={className:"attribute",begin:" [a-zA-Z]+",end:"^"};hljs.HTML_VALUE={className:"value",begin:"[a-zA-Z0-9]+",end:"^"};hljs.LANGUAGES.html={defaultMode:{contains:["tag","comment","doctype","vbscript"]},case_insensitive:true,modes:[hljs.XML_COMMENT,hljs.HTML_DOCTYPE,{className:"tag",lexems:[hljs.IDENT_RE],keywords:hljs.HTML_TAGS,begin:"<style",end:">",contains:["attribute"],illegal:"[\\+\\.]",starts:"css"},{className:"tag",lexems:[hljs.IDENT_RE],keywords:hljs.HTML_TAGS,begin:"<script",end:">",contains:["attribute"],illegal:"[\\+\\.]",starts:"javascript"},{className:"tag",lexems:[hljs.IDENT_RE],keywords:hljs.HTML_TAGS,begin:"<[A-Za-z/]",end:">",contains:["attribute"],illegal:"[\\+\\.]"},{className:"css",end:"</style>",returnEnd:true,subLanguage:"css"},{className:"javascript",end:"<\/script>",returnEnd:true,subLanguage:"javascript"},hljs.HTML_ATTR,hljs.HTML_SHORT_ATTR,hljs.XML_VALUE_QUOT,hljs.XML_VALUE_APOS,hljs.HTML_VALUE,{className:"vbscript",begin:"<%",end:"%>",subLanguage:"vbscript"}]};hljs.LANGUAGES.java={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["javadoc","comment","string","class","number","annotation"],keywords:{"false":1,"synchronized":1,"int":1,"abstract":1,"float":1,"private":1,"char":1,"interface":1,"boolean":1,"static":1,"null":1,"if":1,"const":1,"for":1,"true":1,"while":1,"long":1,"throw":1,strictfp:1,"finally":1,"protected":1,"extends":1,"import":1,"native":1,"final":1,"implements":1,"return":1,"void":1,"enum":1,"else":1,"break":1,"transient":1,"new":1,"catch":1,"instanceof":1,"byte":1,"super":1,"class":1,"volatile":1,"case":1,assert:1,"short":1,"package":1,"default":1,"double":1,"public":1,"try":1,"this":1,"switch":1,"continue":1,"throws":1}},modes:[{className:"class",lexems:[hljs.UNDERSCORE_IDENT_RE],begin:"(class |interface )",end:"{",illegal:":",keywords:{"class":1,"interface":1},contains:["inheritance","title"]},{className:"inheritance",begin:"(implements|extends)",end:"^",noMarkup:true,lexems:[hljs.IDENT_RE],keywords:{"extends":1,"implements":1},relevance:10},{className:"title",begin:hljs.UNDERSCORE_IDENT_RE,end:"^"},{className:"params",begin:"\\(",end:"\\)",contains:["string","annotation"]},hljs.C_NUMBER_MODE,hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,hljs.C_LINE_COMMENT_MODE,{className:"javadoc",begin:"/\\*\\*",end:"\\*/",contains:["javadoctag"],relevance:10},{className:"javadoctag",begin:"@[A-Za-z]+",end:"^"},hljs.C_BLOCK_COMMENT_MODE,{className:"annotation",begin:"@[A-Za-z]+",end:"^"}]};hljs.LANGUAGES.javascript={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["string","comment","number","regexp_container","function"],keywords:{keyword:{"in":1,"if":1,"for":1,"while":1,"finally":1,"var":1,"new":1,"function":1,"do":1,"return":1,"void":1,"else":1,"break":1,"catch":1,"instanceof":1,"with":1,"throw":1,"case":1,"default":1,"try":1,"this":1,"switch":1,"continue":1,"typeof":1,"delete":1},literal:{"true":1,"false":1,"null":1}}},modes:[hljs.C_LINE_COMMENT_MODE,hljs.C_BLOCK_COMMENT_MODE,hljs.C_NUMBER_MODE,hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,{className:"regexp_container",begin:"("+hljs.RE_STARTERS_RE+"|case|return|throw)\\s*",end:"^",noMarkup:true,lexems:[hljs.IDENT_RE],keywords:{"return":1,"throw":1,"case":1},contains:["comment","regexp"],relevance:0},{className:"regexp",begin:"/.*?[^\\\\/]/[gim]*",end:"^"},{className:"function",begin:"\\bfunction\\b",end:"{",lexems:[hljs.UNDERSCORE_IDENT_RE],keywords:{"function":1},contains:["title","params"]},{className:"title",begin:"[A-Za-z$_][0-9A-Za-z$_]*",end:"^"},{className:"params",begin:"\\(",end:"\\)",contains:["string","comment"]}]};hljs.LANGUAGES.lisp=function(){var a="[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#]*";var b="(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s)(\\+|\\-)?\\d+)?";return{case_insensitive:true,defaultMode:{lexems:[a],contains:["literal","number","string","comment","quoted","list"],illegal:"[^\\s]"},modes:[{className:"string",begin:'"',end:'"',contains:["escape"],relevance:0},hljs.BACKSLASH_ESCAPE,{className:"number",begin:b,end:"^"},{className:"number",begin:"#b[0-1]+(/[0-1]+)?",end:"^"},{className:"number",begin:"#o[0-7]+(/[0-7]+)?",end:"^"},{className:"number",begin:"#x[0-9a-f]+(/[0-9a-f]+)?",end:"^"},{className:"number",begin:"#c\\("+b+" +"+b,end:"\\)"},{className:"comment",begin:";",end:"$"},{className:"quoted",begin:"['`]\\(",end:"\\)",contains:["number","string","variable","keyword","quoted_list"]},{className:"quoted",begin:"\\(quote ",end:"\\)",contains:["number","string","variable","keyword","quoted_list"],lexems:[a],keywords:{title:{quote:1}}},{className:"quoted_list",begin:"\\(",end:"\\)",contains:["quoted_list","literal","number","string"]},{className:"list",begin:"\\(",end:"\\)",contains:["title","body"]},{className:"title",begin:a,end:"^",endsWithParent:true},{className:"body",begin:"^",endsWithParent:true,excludeEnd:true,contains:["quoted","list","literal","number","string","comment","variable","keyword"]},{className:"keyword",begin:"[:&]"+a,end:"^"},{className:"variable",begin:"\\*",end:"\\*"},{className:"literal",begin:"\\b(t{1}|nil)\\b",end:"^"}]}}();hljs.LANGUAGES.php={defaultMode:{lexems:[hljs.IDENT_RE],contains:["comment","number","string","variable","preprocessor"],keywords:{and:1,include_once:1,list:1,"abstract":1,global:1,"private":1,echo:1,"interface":1,as:1,"static":1,endswitch:1,array:1,"null":1,"if":1,endwhile:1,or:1,"const":1,"for":1,endforeach:1,self:1,"var":1,"while":1,isset:1,"public":1,"protected":1,exit:1,foreach:1,"throw":1,elseif:1,"extends":1,include:1,__FILE__:1,empty:1,require_once:1,"function":1,"do":1,xor:1,"return":1,"implements":1,parent:1,clone:1,use:1,__CLASS__:1,__LINE__:1,"else":1,"break":1,print:1,"eval":1,"new":1,"catch":1,__METHOD__:1,"class":1,"case":1,exception:1,php_user_filter:1,"default":1,die:1,require:1,__FUNCTION__:1,enddeclare:1,"final":1,"try":1,"this":1,"switch":1,"continue":1,endfor:1,endif:1,declare:1,unset:1}},case_insensitive:true,modes:[hljs.C_LINE_COMMENT_MODE,hljs.HASH_COMMENT_MODE,{className:"comment",begin:"/\\*",end:"\\*/",contains:["phpdoc"]},{className:"phpdoc",begin:"\\s@[A-Za-z]+",end:"^",relevance:10},hljs.C_NUMBER_MODE,{className:"string",begin:"'",end:"'",contains:["escape"],relevance:0},{className:"string",begin:'"',end:'"',contains:["escape"],relevance:0},hljs.BACKSLASH_ESCAPE,{className:"variable",begin:"\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*",end:"^"},{className:"preprocessor",begin:"<\\?php",end:"^",relevance:10},{className:"preprocessor",begin:"\\?>",end:"^"}]};hljs.LANGUAGES.python={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],illegal:"(</|->)",contains:["comment","string","function","class","number","decorator"],keywords:{keyword:{and:1,elif:1,is:1,global:1,as:1,"in":1,"if":1,from:1,raise:1,"for":1,except:1,"finally":1,print:1,"import":1,pass:1,"return":1,exec:1,"else":1,"break":1,not:1,"with":1,"class":1,assert:1,yield:1,"try":1,"while":1,"continue":1,del:1,or:1,def:1,lambda:1,nonlocal:10},built_in:{None:1,True:1,False:1,Ellipsis:1,NotImplemented:1}}},modes:[{className:"function",lexems:[hljs.UNDERSCORE_IDENT_RE],begin:"\\bdef ",end:":",illegal:"$",keywords:{def:1},contains:["title","params"],relevance:10},{className:"class",lexems:[hljs.UNDERSCORE_IDENT_RE],begin:"\\bclass ",end:":",illegal:"[${]",keywords:{"class":1},contains:["title","params",],relevance:10},{className:"title",begin:hljs.UNDERSCORE_IDENT_RE,end:"^"},{className:"params",begin:"\\(",end:"\\)",contains:["string"]},hljs.HASH_COMMENT_MODE,hljs.C_NUMBER_MODE,{className:"string",begin:"u?r?'''",end:"'''",relevance:10},{className:"string",begin:'u?r?"""',end:'"""',relevance:10},hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,{className:"string",begin:"(u|r|ur)'",end:"'",contains:["escape"],relevance:10},{className:"string",begin:'(u|r|ur)"',end:'"',contains:["escape"],relevance:10},{className:"decorator",begin:"@",end:"$"}]};hljs.LANGUAGES.profile={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["number","builtin","filename","header","summary","string","function"]},modes:[hljs.C_NUMBER_MODE,hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,{className:"summary",begin:"function calls",end:"$",contains:["number"],relevance:10},{className:"header",begin:"(ncalls|tottime|cumtime)",end:"$",lexems:[hljs.IDENT_RE],keywords:{ncalls:1,tottime:10,cumtime:10,filename:1},relevance:10},{className:"function",begin:"\\(",end:"\\)",lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["title"]},{className:"title",begin:hljs.UNDERSCORE_IDENT_RE,end:"^"},{className:"builtin",begin:"{",end:"}",contains:["string"],excludeBegin:true,excludeEnd:true},{className:"filename",begin:"(/w|[a-zA-Z_][\da-zA-Z_]+\\.[\da-zA-Z_]{1,3})",end:":",excludeEnd:true}]};hljs.LANGUAGES.ruby=function(){var a="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?";var c="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var b=["comment","string","char","class","function","constant","symbol","number","variable","identifier","regexp_container"];var d={keyword:{and:1,"false":1,then:1,defined:1,module:1,"in":1,"return":1,redo:1,"if":1,BEGIN:1,retry:1,end:1,"for":1,"true":1,self:1,when:1,next:1,until:1,"do":1,begin:1,unless:1,END:1,rescue:1,nil:1,"else":1,"break":1,undef:1,not:1,"super":1,"class":1,"case":1,require:1,yield:1,alias:1,"while":1,ensure:1,elsif:1,or:1,def:1},keymethods:{__id__:1,__send__:1,abort:1,abs:1,"all?":1,allocate:1,ancestors:1,"any?":1,arity:1,assoc:1,at:1,at_exit:1,autoload:1,"autoload?":1,"between?":1,binding:1,binmode:1,"block_given?":1,call:1,callcc:1,caller:1,capitalize:1,"capitalize!":1,casecmp:1,"catch":1,ceil:1,center:1,chomp:1,"chomp!":1,chop:1,"chop!":1,chr:1,"class":1,class_eval:1,"class_variable_defined?":1,class_variables:1,clear:1,clone:1,close:1,close_read:1,close_write:1,"closed?":1,coerce:1,collect:1,"collect!":1,compact:1,"compact!":1,concat:1,"const_defined?":1,const_get:1,const_missing:1,const_set:1,constants:1,count:1,crypt:1,"default":1,default_proc:1,"delete":1,"delete!":1,delete_at:1,delete_if:1,detect:1,display:1,div:1,divmod:1,downcase:1,"downcase!":1,downto:1,dump:1,dup:1,each:1,each_byte:1,each_index:1,each_key:1,each_line:1,each_pair:1,each_value:1,each_with_index:1,"empty?":1,entries:1,eof:1,"eof?":1,"eql?":1,"equal?":1,"eval":1,exec:1,exit:1,"exit!":1,extend:1,fail:1,fcntl:1,fetch:1,fileno:1,fill:1,find:1,find_all:1,first:1,flatten:1,"flatten!":1,floor:1,flush:1,for_fd:1,foreach:1,fork:1,format:1,freeze:1,"frozen?":1,fsync:1,getc:1,gets:1,global_variables:1,grep:1,gsub:1,"gsub!":1,"has_key?":1,"has_value?":1,hash:1,hex:1,id:1,include:1,"include?":1,included_modules:1,index:1,indexes:1,indices:1,induced_from:1,inject:1,insert:1,inspect:1,instance_eval:1,instance_method:1,instance_methods:1,"instance_of?":1,"instance_variable_defined?":1,instance_variable_get:1,instance_variable_set:1,instance_variables:1,"integer?":1,intern:1,invert:1,ioctl:1,"is_a?":1,isatty:1,"iterator?":1,join:1,"key?":1,keys:1,"kind_of?":1,lambda:1,last:1,length:1,lineno:1,ljust:1,load:1,local_variables:1,loop:1,lstrip:1,"lstrip!":1,map:1,"map!":1,match:1,max:1,"member?":1,merge:1,"merge!":1,method:1,"method_defined?":1,method_missing:1,methods:1,min:1,module_eval:1,modulo:1,name:1,nesting:1,"new":1,next:1,"next!":1,"nil?":1,nitems:1,"nonzero?":1,object_id:1,oct:1,open:1,pack:1,partition:1,pid:1,pipe:1,pop:1,popen:1,pos:1,prec:1,prec_f:1,prec_i:1,print:1,printf:1,private_class_method:1,private_instance_methods:1,"private_method_defined?":1,private_methods:1,proc:1,protected_instance_methods:1,"protected_method_defined?":1,protected_methods:1,public_class_method:1,public_instance_methods:1,"public_method_defined?":1,public_methods:1,push:1,putc:1,puts:1,quo:1,raise:1,rand:1,rassoc:1,read:1,read_nonblock:1,readchar:1,readline:1,readlines:1,readpartial:1,rehash:1,reject:1,"reject!":1,remainder:1,reopen:1,replace:1,require:1,"respond_to?":1,reverse:1,"reverse!":1,reverse_each:1,rewind:1,rindex:1,rjust:1,round:1,rstrip:1,"rstrip!":1,scan:1,seek:1,select:1,send:1,set_trace_func:1,shift:1,singleton_method_added:1,singleton_methods:1,size:1,sleep:1,slice:1,"slice!":1,sort:1,"sort!":1,sort_by:1,split:1,sprintf:1,squeeze:1,"squeeze!":1,srand:1,stat:1,step:1,store:1,strip:1,"strip!":1,sub:1,"sub!":1,succ:1,"succ!":1,sum:1,superclass:1,swapcase:1,"swapcase!":1,sync:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,taint:1,"tainted?":1,tell:1,test:1,"throw":1,times:1,to_a:1,to_ary:1,to_f:1,to_hash:1,to_i:1,to_int:1,to_io:1,to_proc:1,to_s:1,to_str:1,to_sym:1,tr:1,"tr!":1,tr_s:1,"tr_s!":1,trace_var:1,transpose:1,trap:1,truncate:1,"tty?":1,type:1,ungetc:1,uniq:1,"uniq!":1,unpack:1,unshift:1,untaint:1,untrace_var:1,upcase:1,"upcase!":1,update:1,upto:1,"value?":1,values:1,values_at:1,warn:1,write:1,write_nonblock:1,"zero?":1,zip:1}};return{defaultMode:{lexems:[a],contains:b,keywords:d},modes:[{className:"comment",begin:"#",end:"$",contains:["yardoctag"]},{className:"yardoctag",begin:"@[A-Za-z]+",end:"^"},{className:"comment",begin:"^\\=begin",end:"^\\=end",contains:["yardoctag"],relevance:10},{className:"comment",begin:"^__END__",end:"\\n$"},{className:"params",begin:"\\(",end:"\\)",lexems:[a],keywords:d,contains:b},{className:"function",begin:"\\bdef\\s+",end:" |$|;",lexems:[a],keywords:d,contains:["ftitle","params","comment"]},{className:"ftitle",begin:c,end:"^",lexems:[a],keywords:d},{className:"class",begin:"\\b(class|module)\\b",end:"$|;",lexems:[hljs.UNDERSCORE_IDENT_RE],keywords:d,contains:["title","inheritance","comment"],keywords:{"class":1,module:1}},{className:"title",begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",end:"^",relevance:0},{className:"inheritance",begin:"<\\s*",end:"^",contains:["parent"]},{className:"parent",begin:"("+hljs.IDENT_RE+"::)?"+hljs.IDENT_RE,end:"^"},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",end:"^",relevance:0},{className:"number",begin:"\\?\\w",end:"^"},{className:"string",begin:"'",end:"'",contains:["escape","subst"],relevance:0},{className:"string",begin:'"',end:'"',contains:["escape","subst"],relevance:0},{className:"string",begin:"%[qw]?\\(",end:"\\)",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?\\[",end:"\\]",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?{",end:"}",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?<",end:">",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?/",end:"/",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?%",end:"%",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?-",end:"-",contains:["escape","subst"],relevance:10},{className:"string",begin:"%[qw]?\\|",end:"\\|",contains:["escape","subst"],relevance:10},{className:"constant",begin:"(::)?([A-Z]\\w*(::)?)+",end:"^"},{className:"symbol",begin:":",end:"^",contains:["string","identifier"]},{className:"identifier",begin:a,end:"^",lexems:[a],keywords:d},hljs.BACKSLASH_ESCAPE,{className:"subst",begin:"#\\{",end:"}",lexems:[a],keywords:d,contains:b},{className:"regexp_container",begin:"("+hljs.RE_STARTERS_RE+")\\s*",end:"^",noMarkup:true,contains:["comment","regexp"],relevance:0},{className:"regexp",begin:"/",end:"/[a-z]*",illegal:"\\n",contains:["escape"]},{className:"variable",begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))",end:"^"}]}}();hljs.LANGUAGES.scala={defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["javadoc","comment","string","class","number","annotation"],keywords:{type:1,yield:1,lazy:1,override:1,def:1,"with":1,val:1,"var":1,"false":1,"true":1,sealed:1,"abstract":1,"private":1,trait:1,object:1,"null":1,"if":1,"for":1,"while":1,"throw":1,"finally":1,"protected":1,"extends":1,"import":1,"final":1,"return":1,"else":1,"break":1,"new":1,"catch":1,"super":1,"class":1,"case":1,"package":1,"default":1,"try":1,"this":1,match:1,"continue":1,"throws":1}},modes:[{className:"class",lexems:[hljs.UNDERSCORE_IDENT_RE],begin:"((case )?class |object |trait )",end:"({|$)",illegal:":",keywords:{"case":1,"class":1,trait:1,object:1},contains:["inheritance","title","params"]},{className:"inheritance",begin:"(extends|with)",end:"^",noMarkup:true,lexems:[hljs.IDENT_RE],keywords:{"extends":1,"with":1},relevance:10},{className:"title",begin:hljs.UNDERSCORE_IDENT_RE,end:"^"},{className:"params",begin:"\\(",end:"\\)",contains:["string","annotation"]},hljs.C_NUMBER_MODE,hljs.APOS_STRING_MODE,hljs.QUOTE_STRING_MODE,hljs.BACKSLASH_ESCAPE,hljs.C_LINE_COMMENT_MODE,{className:"javadoc",begin:"/\\*\\*",end:"\\*/",contains:["javadoctag"],relevance:10},{className:"javadoctag",begin:"@[A-Za-z]+",end:"^"},hljs.C_BLOCK_COMMENT_MODE,{className:"annotation",begin:"@[A-Za-z]+",end:"^"},{className:"string",begin:'u?r?"""',end:'"""',relevance:10}]};hljs.LANGUAGES.smalltalk=function(){var a="[a-z][a-zA-Z0-9_]*";return{defaultMode:{lexems:[hljs.UNDERSCORE_IDENT_RE],contains:["comment","string","class","method","number","symbol","char","localvars","array"],keywords:{self:1,"super":1,nil:1,"true":1,"false":1,thisContext:1}},modes:[{className:"class",begin:"\\b[A-Z][A-Za-z0-9_]*",end:"^",relevance:0},{className:"symbol",begin:"#"+hljs.UNDERSCORE_IDENT_RE,end:"^"},hljs.C_NUMBER_MODE,hljs.APOS_STRING_MODE,{className:"comment",begin:'"',end:'"',relevance:0},{className:"method",begin:a+":",end:"^"},{className:"char",begin:"\\$.{1}",end:"^"},{className:"localvars",begin:"\\|\\s*(("+a+")\\s*)+\\|",end:"^",relevance:10},{className:"array",begin:"\\#\\(",end:"\\)",contains:["string","char","number","symbol"]}]}}();
+
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image.png b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image.png
new file mode 100644
index 0000000..8f390ce
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image.png
Binary files differ
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image1.png b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image1.png
new file mode 100644
index 0000000..2790f50
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/image1.png
Binary files differ
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_002.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_002.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_002.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_003.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_003.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_003.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_004.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_004.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_004.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_005.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_005.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_005.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_006.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_006.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_006.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_007.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_007.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_007.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_008.php b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_008.php
new file mode 100644
index 0000000..ad0e584
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/in_008.php
@@ -0,0 +1 @@
+var o_O \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/jquery.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/jquery.js
new file mode 100644
index 0000000..7c24308
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/jquery.js
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/pipeline.png b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/pipeline.png
new file mode 100644
index 0000000..e632401
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/pipeline.png
Binary files differ
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/show_ads.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/show_ads.js
new file mode 100644
index 0000000..ec8b35f
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/show_ads.js
@@ -0,0 +1,27 @@
+(function(){var aa=function(a,b,c){return a.call.apply(a.bind,arguments)},ba=function(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}},e=function(a,b,c){e=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?aa:ba;return e.apply(null,arguments)};var h=(new Date).getTime();var k=function(a){a=parseFloat(a);return isNaN(a)||1<a||0>a?0:a},ca=/^([\w-]+\.)*([\w-]{2,})(\:[0-9]+)?$/,da=function(a,b){if(!a)return b;var c=a.match(ca);return c?c[0]:b};var ea=k("0.15"),fa=k("0.005"),ga=k("1.0"),ha=k("0.005"),ia=k("0.01");var ja=/^true$/.test("false")?!0:!1;var ka=function(){return da("","pagead2.googlesyndication.com")};var la=/&/g,ma=/</g,na=/>/g,qa=/\"/g,ra={"\x00":"\\0","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\x0B",'"':'\\"',"\\":"\\\\"},l={"'":"\\'"};var sa=window,n,ta=null,r=document.getElementsByTagName("script");r&&r.length&&(ta=r[r.length-1].parentNode);n=ta;ka();var ua=function(a,b){for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&b.call(null,a[c],c,a)},s=function(a){return!!a&&"function"==typeof a&&!!a.call},va=function(a,b){if(!(2>arguments.length))for(var c=1,d=arguments.length;c<d;++c)a.push(arguments[c])};function wa(a,b){xa(a,"load",b)}
+var xa=function(a,b,c,d){return a.addEventListener?(a.addEventListener(b,c,d||!1),!0):a.attachEvent?(a.attachEvent("on"+b,c),!0):!1},ya=function(a,b,c,d){c=e(d,c);return xa(a,b,c,void 0)?c:null},za=function(a,b,c){a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c)},u=function(a,b){if(!(1E-4>Math.random())){var c=Math.random();if(c<b)return a[Math.floor(c/b*a.length)]}return null},Aa=function(a){try{return!!a.location.href||""===a.location.href}catch(b){return!1}};var Ba=null,Ca=function(){if(!Ba){for(var a=window,b=a,c=0;a!=a.parent;)if(a=a.parent,c++,Aa(a))b=a;else break;Ba=b}return Ba};var v,w=function(a){this.c=[];this.b=a||window;this.a=0;this.d=null},Da=function(a,b){this.l=a;this.win=b};w.prototype.p=function(a,b){0!=this.a||0!=this.c.length||b&&b!=window?this.g(a,b):(this.a=2,this.f(new Da(a,window)))};w.prototype.g=function(a,b){this.c.push(new Da(a,b||this.b));Ea(this)};w.prototype.q=function(a){this.a=1;a&&(this.d=this.b.setTimeout(e(this.e,this),a))};w.prototype.e=function(){1==this.a&&(null!=this.d&&(this.b.clearTimeout(this.d),this.d=null),this.a=0);Ea(this)};
+w.prototype.r=function(){return!0};w.prototype.nq=w.prototype.p;w.prototype.nqa=w.prototype.g;w.prototype.al=w.prototype.q;w.prototype.rl=w.prototype.e;w.prototype.sz=w.prototype.r;var Ea=function(a){a.b.setTimeout(e(a.o,a),0)};w.prototype.o=function(){if(0==this.a&&this.c.length){var a=this.c.shift();this.a=2;a.win.setTimeout(e(this.f,this,a),0);Ea(this)}};w.prototype.f=function(a){this.a=0;a.l()};
+var Fa=function(a){try{return a.sz()}catch(b){return!1}},Ga=function(a){return!!a&&("object"==typeof a||"function"==typeof a)&&Fa(a)&&s(a.nq)&&s(a.nqa)&&s(a.al)&&s(a.rl)},Ha=function(){if(v&&Fa(v))return v;var a=Ca(),b=a.google_jobrunner;return Ga(b)?v=b:a.google_jobrunner=v=new w(a)},Ia=function(a,b){Ha().nq(a,b)},Ja=function(a,b){Ha().nqa(a,b)};var Ka=/MSIE [2-7]|PlayStation|Gecko\/20090226|Android 2\./i,La=/Android|Opera/;var Ma=function(a,b,c){c||(c=ja?"https":"http");return[c,"://",a,b].join("")};var Na=function(){},Pa=function(a,b,c){switch(typeof b){case "string":Oa(b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(null==b){c.push("null");break}if(b instanceof Array){var d=b.length;c.push("[");for(var f="",g=0;g<d;g++)c.push(f),Pa(a,b[g],c),f=",";c.push("]");break}c.push("{");d="";for(f in b)b.hasOwnProperty(f)&&(g=b[f],"function"!=typeof g&&(c.push(d),Oa(f,c),c.push(":"),Pa(a,g,c),
+d=","));c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}},Qa={'"':'\\"',"\\":"\\\\","/":"\\/","\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\x0B":"\\u000b"},Ra=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g,Oa=function(a,b){b.push('"');b.push(a.replace(Ra,function(a){if(a in Qa)return Qa[a];var b=a.charCodeAt(0),f="\\u";16>b?f+="000":256>b?f+="00":4096>b&&(f+="0");return Qa[a]=f+b.toString(16)}));b.push('"')};var x="google_ad_block google_ad_channel google_ad_client google_ad_format google_ad_height google_ad_host google_ad_host_channel google_ad_host_tier_id google_ad_output google_ad_override google_ad_region google_ad_section google_ad_slot google_ad_type google_ad_width google_adtest google_allow_expandable_ads google_alternate_ad_url google_alternate_color google_analytics_domain_name google_analytics_uacct google_bid google_city google_color_bg google_color_border google_color_line google_color_link google_color_text google_color_url google_container_id google_contents google_country google_cpm google_ctr_threshold google_cust_age google_cust_ch google_cust_gender google_cust_id google_cust_interests google_cust_job google_cust_l google_cust_lh google_cust_u_url google_disable_video_autoplay google_ed google_eids google_enable_ose google_encoding google_floating_ad_position google_font_face google_font_size google_frame_id google_gl google_hints google_image_size google_kw google_kw_type google_lact google_language google_loeid google_max_num_ads google_max_radlink_len google_mtl google_num_radlinks google_num_radlinks_per_unit google_num_slots_to_rotate google_only_ads_with_video google_only_pyv_ads google_only_userchoice_ads google_override_format google_page_url google_previous_watch google_previous_searches google_referrer_url google_region google_reuse_colors google_rl_dest_url google_rl_filtering google_rl_mode google_rt google_safe google_sc_id google_scs google_sui google_skip google_tag_info google_targeting google_tdsma google_tfs google_tl google_ui_features google_ui_version google_video_doc_id google_video_product_type google_video_url_to_fetch google_with_pyv_ads google_yt_pt google_yt_up".split(" "),
+Sa=function(){var a=y;a.google_page_url&&(a.google_page_url=String(a.google_page_url));var b=[];ua(a,function(a,d){if(null!=a){var f;try{var g=[];Pa(new Na,a,g);f=g.join("")}catch(p){}f&&va(b,d,"=",f,";")}});return b.join("")};var Ta=/\.((google(|groups|mail|images|print))|gmail)\./,Ua=function(){var a=z,b=Ta.test(a.location.host);return!(!a.postMessage||!a.localStorage||!a.JSON||b)};var Va=function(a){this.b=a;a.google_iframe_oncopy||(a.google_iframe_oncopy={handlers:{}});this.m=a.google_iframe_oncopy},Wa;var A="var i=this.id,s=window.google_iframe_oncopy,H=s&&s.handlers,h=H&&H[i],w=this.contentWindow,d;try{d=w.document}catch(e){}if(h&&d&&(!d.body||!d.body.firstChild)){if(h.call){setTimeout(h,0)}else if(h.match){w.location.replace(h)}}";
+/[&<>\"]/.test(A)&&(-1!=A.indexOf("&")&&(A=A.replace(la,"&amp;")),-1!=A.indexOf("<")&&(A=A.replace(ma,"&lt;")),-1!=A.indexOf(">")&&(A=A.replace(na,"&gt;")),-1!=A.indexOf('"')&&(A=A.replace(qa,"&quot;")));Wa=A;Va.prototype.set=function(a,b){this.m.handlers[a]=b;this.b.addEventListener&&!/MSIE/.test(navigator.userAgent)&&this.b.addEventListener("load",e(this.n,this,a),!1)};Va.prototype.n=function(a){a=this.b.document.getElementById(a);var b=a.contentWindow.document;if(a.onload&&b&&(!b.body||!b.body.firstChild))a.onload()};var Xa=function(a){a=a.google_unique_id;return"number"==typeof a?a:0},Za=function(){var a="script";return["<",a,' src="',Ma(ka(),"/pagead/js/r20130626/r20130206/show_ads_impl.js",""),'"></',a,">"].join("")},$a=function(a,b,c,d){return function(){var f=!1;d&&Ha().al(3E4);try{if(Aa(a.document.getElementById(b).contentWindow)){var g=a.document.getElementById(b).contentWindow,
+p=g.document;p.body&&p.body.firstChild||(p.open(),g.google_async_iframe_close=!0,p.write(c))}else{var Q=a.document.getElementById(b).contentWindow,oa;g=c;g=String(g);if(g.quote)oa=g.quote();else{for(var p=['"'],R=0;R<g.length;R++){var S=g.charAt(R),Ya=S.charCodeAt(0),Yb=p,Zb=R+1,pa;if(!(pa=ra[S])){var D;if(31<Ya&&127>Ya)D=S;else{var q=S;if(q in l)D=l[q];else if(q in ra)D=l[q]=ra[q];else{var m=q,t=q.charCodeAt(0);if(31<t&&127>t)m=q;else{if(256>t){if(m="\\x",16>t||256<t)m+="0"}else m="\\u",4096>t&&
+(m+="0");m+=t.toString(16).toUpperCase()}D=l[q]=m}}pa=D}Yb[Zb]=pa}p.push('"');oa=p.join("")}Q.location.replace("javascript:"+oa)}f=!0}catch(nc){Q=Ca().google_jobrunner,Ga(Q)&&Q.rl()}f&&(new Va(a)).set(b,$a(a,b,c,!1))}},ab=function(){var a=["<iframe"];ua(B,function(b,c){a.push(" "+c+'="'+(null==b?"":b)+'"')});a.push("></iframe>");return a.join("")},db=function(a,b){var c=bb,d=b?'"':"",f=d+"0"+d;a.width=d+cb+d;a.height=d+c+d;a.frameborder=f;a.marginwidth=f;a.marginheight=f;a.vspace=f;a.hspace=f;a.allowtransparency=
+d+"true"+d;a.scrolling=d+"no"+d},eb=Math.floor(1E6*Math.random()),fb=function(a){for(var b=a.data.split("\n"),c={},d=0;d<b.length;d++){var f=b[d].indexOf("=");-1!=f&&(c[b[d].substr(0,f)]=b[d].substr(f+1))}b=c[3];if(c[1]==eb&&(window.google_top_js_status=4,a.source==top&&0==b.indexOf(a.origin)&&(window.google_top_values=c,window.google_top_js_status=5),window.google_top_js_callbacks)){for(a=0;a<window.google_top_js_callbacks.length;a++)window.google_top_js_callbacks[a]();window.google_top_js_callbacks.length=
+0}};var gb=function(a,b,c){this.x=a;this.y=b;this.z=c},hb=function(a,b,c){this.beta=a;this.gamma=b;this.alpha=c},jb=function(){var a=C,b=ib;this.deviceAccelerationWithGravity=this.deviceAccelerationWithoutGravity=null;this.deviceMotionEventCallbacks=[];this.deviceOrientation=null;this.deviceOrientationEventCallbacks=[];this.isDeviceOrientationEventListenerRegistered=this.isDeviceMotionEventListenerRegistered=this.didDeviceOrientationCallbacksTimeoutExpire=this.didDeviceMotionCallbacksTimeoutExpire=!1;
+this.registeredMozOrientationEventListener=this.registeredDeviceOrientationEventListener=this.registeredDeviceMotionEventListener=null;this.sensorsExperiment=b;this.stopTimeStamp=this.startTimeStamp=null;this.win=a},E=function(a){this.a=a;this.a.win.DeviceOrientationEvent?(this.a.registeredDeviceOrientationEventListener=ya(this.a.win,"deviceorientation",this,this.j),this.a.isDeviceOrientationEventListenerRegistered=!0):this.a.win.OrientationEvent&&(this.a.registeredMozOrientationEventListener=ya(this.a.win,
+"MozOrientation",this,this.k),this.a.isDeviceOrientationEventListenerRegistered=!0);this.a.win.DeviceMotionEvent&&(this.a.registeredDeviceMotionEventListener=ya(this.a.win,"devicemotion",this,this.i),this.a.isDeviceMotionEventListenerRegistered=!0)};
+E.prototype.i=function(a){a.acceleration&&(this.a.deviceAccelerationWithoutGravity=new gb(a.acceleration.x,a.acceleration.y,a.acceleration.z));a.accelerationIncludingGravity&&(this.a.deviceAccelerationWithGravity=new gb(a.accelerationIncludingGravity.x,a.accelerationIncludingGravity.y,a.accelerationIncludingGravity.z));kb(this.a.deviceMotionEventCallbacks);za(this.a.win,"devicemotion",this.a.registeredDeviceMotionEventListener)};
+E.prototype.j=function(a){this.a.deviceOrientation=new hb(a.beta,a.gamma,a.alpha);kb(this.a.deviceOrientationEventCallbacks);za(this.a.win,"deviceorientation",this.a.registeredDeviceOrientationEventListener)};E.prototype.k=function(a){this.a.deviceOrientation=new hb(-90*a.y,90*a.x,null);kb(this.a.deviceOrientationEventCallbacks);za(this.a.win,"MozOrientation",this.a.registeredMozOrientationEventListener)};var kb=function(a){for(var b=0;b<a.length;++b)a[b]();a.length=0};(function(a){"google_onload_fired"in a||(a.google_onload_fired=!1,wa(a,function(){a.google_onload_fired=!0}))})(window);
+if(!window.google_top_experiment){var lb=window;if(2!==(lb.top==lb?0:Aa(lb.top)?1:2))window.google_top_js_status=0;else if(top.postMessage){var mb;try{mb=top.frames.google_top_static_frame?!0:!1}catch(nb){mb=!1}if(mb){if(window.google_top_experiment=u(["jp_c","jp_zl"],ea)||"jp_wfpmr","jp_zl"===window.google_top_experiment||"jp_wfpmr"===window.google_top_experiment){xa(window,"message",fb);window.google_top_js_status=3;var ob={0:"google_loc_request",1:eb},pb=[],qb;for(qb in ob)pb.push(qb+"="+ob[qb]);
+top.postMessage(pb.join("\n"),"*")}}else window.google_top_js_status=2}else window.google_top_js_status=1}var F=void 0,F=F||window,rb=!1;if(F.navigator&&F.navigator.userAgent)var sb=F.navigator.userAgent,rb=0!=sb.indexOf("Opera")&&-1!=sb.indexOf("WebKit")&&-1!=sb.indexOf("Mobile");
+if(rb){var C=window;if(!/Android/.test(C.navigator.userAgent)&&0==Xa(C)&&!C.google_sensors){var ib,tb=null,ub=C;ub.google_top_experiment&&"jp_c"!=ub.google_top_experiment||(tb=u(["ds_c","ds_zl","ds_wfea"],ia));if(ib=tb)C.google_sensors=new jb,"ds_c"!=ib&&new E(C.google_sensors)}}var vb;
+if(!(vb=!1===window.google_enable_async)){var wb;var xb=navigator.userAgent;Ka.test(xb)?wb=!1:(void 0!==window.google_async_for_oa_experiment||(!La.test(navigator.userAgent)||Ka.test(navigator.userAgent))||(window.google_async_for_oa_experiment=u(["C","E"],ha)),wb=La.test(xb)?"E"===window.google_async_for_oa_experiment:!0);vb=!wb||window.google_container_id||window.google_ad_output&&"html"!=window.google_ad_output}
+if(vb)window.google_loader_used="sb",window.google_start_time=h,document.write(Za());else{var yb=window;yb.google_unique_id?++yb.google_unique_id:yb.google_unique_id=1;for(var z=window,y,zb={},Ab=0,Bb=x.length;Ab<Bb;Ab++){var Cb=x[Ab];null!=z[Cb]&&(zb[Cb]=z[Cb])}y=zb;y.google_loader_used="sa";for(var Db=0,Eb=x.length;Db<Eb;Db++)z[x[Db]]=null;var cb=y.google_ad_width,bb=y.google_ad_height,G={};db(G,!0);G.onload='"'+Wa+'"';for(var H,Fb=y,Gb=z.document,I=G.id,Hb=0;!I||Gb.getElementById(I);)I="aswift_"+
+Hb++;G.id=I;G.name=I;var Ib=Fb.google_ad_width,Jb=Fb.google_ad_height,J=["<iframe"],K;for(K in G)G.hasOwnProperty(K)&&va(J,K+"="+G[K]);J.push('style="left:0;position:absolute;top:0;"');J.push("></iframe>");var Kb="border:none;height:"+Jb+"px;margin:0;padding:0;position:relative;visibility:visible;width:"+Ib+"px";Gb.write(['<ins style="display:inline-table;',Kb,'"><ins id="',G.id+"_anchor",'" style="display:block;',Kb,'">',J.join(" "),"</ins></ins>"].join(""));H=G.id;var Lb=Sa(),L=y,Mb=L.google_ad_output,
+M=L.google_ad_format;M||"html"!=Mb&&null!=Mb||(M=L.google_ad_width+"x"+L.google_ad_height);var Nb=!L.google_ad_slot||L.google_override_format||"aa"==L.google_loader_used,M=M&&Nb?M.toLowerCase():"";L.google_ad_format=M;var N,O=y||sa,Ob=[O.google_ad_slot,O.google_ad_format,O.google_ad_type,O.google_ad_width,O.google_ad_height];if(n){var P;if(n){for(var Pb=[],Qb=0,T=n;T&&25>Qb;T=T.parentNode,++Qb)Pb.push(9!=T.nodeType&&T.id||"");P=Pb.join()}else P="";P&&Ob.push(P)}var Rb=0;if(Ob){var Sb=Ob.join(":"),
+Tb=Sb.length;if(0==Tb)Rb=0;else{for(var U=305419896,Ub=0;Ub<Tb;Ub++)U^=(U<<5)+(U>>2)+Sb.charCodeAt(Ub)&4294967295;Rb=0<U?U:4294967296+U}}N=Rb.toString();o:{var V=y,W=z.google_async_slots;W||(W=z.google_async_slots={});var X=String(Xa(z));if(X in W&&(X+="b",X in W))break o;W[X]={sent:!1,w:V.google_ad_width||"",h:V.google_ad_height||"",adk:N,type:V.google_ad_type||"",slot:V.google_ad_slot||"",fmt:V.google_ad_format||"",cli:V.google_ad_client||"",saw:[]}}var Y,Vb=Ua(),Wb=3==({visible:1,hidden:2,prerender:3,
+preview:4}[z.document.webkitVisibilityState||z.document.mozVisibilityState||z.document.visibilityState||""]||0);Vb&&(!Wb&&void 0===z.google_ad_handling_experiment)&&(z.google_ad_handling_experiment=u(["XN","EI"],fa)||u(["PC"],ga));Y=z.google_ad_handling_experiment?String(z.google_ad_handling_experiment):null;var Xb;var $b=y;if(Ua()&&1==z.google_unique_id&&"XN"!=Y){var ac="zrt_ads_frame"+z.google_unique_id,bc,cc=$b.google_page_url;if(!cc){var Z;e:{var $=z.document,dc=cb||z.google_ad_width,ec=bb||z.google_ad_height;
+if(z.top==z)Z=!1;else{var fc=$.documentElement;if(dc&&ec){var gc=1,hc=1;z.innerHeight?(gc=z.innerWidth,hc=z.innerHeight):fc&&fc.clientHeight?(gc=fc.clientWidth,hc=fc.clientHeight):$.body&&(gc=$.body.clientWidth,hc=$.body.clientHeight);if(hc>2*ec||gc>2*dc){Z=!1;break e}}Z=!0}}cc=Z?z.document.referrer:z.document.URL}bc=encodeURIComponent(cc);var ic=null;"PC"!=Y&&"EI"!=Y||(ic=("PC"==Y?"K":"I")+"-"+(bc+"/"+N+"/"+z.google_unique_id));var B={};db(B,!1);B.style="display:none";var jc=ic;B.id=ac;B.name=ac;
+B.src=Ma(da("","googleads.g.doubleclick.net"),["/pagead/html/r20130626/r20130206/zrt_lookup.html",jc?"#"+encodeURIComponent(jc):""].join(""));Xb=ab()}else Xb=null;var kc=(new Date).getTime(),lc=z.google_top_experiment,mc=z.google_async_for_oa_experiment,oc=["<!doctype html><html><body>",Xb,"<script>",Lb,"google_show_ads_impl=true;google_unique_id=",z.google_unique_id,';google_async_iframe_id="',H,
+'";google_ad_unit_key="',N,'";google_start_time=',h,";",lc?'google_top_experiment="'+lc+'";':"",Y?'google_ad_handling_experiment="'+Y+'";':"",mc?'google_async_for_oa_experiment="'+mc+'";':"","google_bpp=",kc>h?kc-h:1,";\x3c/script>",Za(),"</body></html>"].join("");(z.document.getElementById(H)?Ia:Ja)($a(z,H,oc,!0))};})();
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/style.css b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/style.css
new file mode 100644
index 0000000..09f97a4
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/style.css
@@ -0,0 +1,151 @@
+body { background: #e9e9e9; margin: 0; font-family: sans-serif; }
+#wrapper { width: 975px; margin: 0 auto; height: auto; }
+#content { width: 635px; float: left; background: #fff; min-height: 600px; padding: 30px 25px; padding-right: 30px; }
+#nav { width: 285px; float: left; color: #666; background: #e9e9e9; }
+#nav-links { padding: 0; margin: 0; list-style: none; margin-bottom: 25px; }
+
+#nav-links li { padding: 0; margin: 0; }
+#nav-links a:link, #nav-links a:visited { display: block; width: 259px; padding: 10px; text-decoration: none; color: #f7f7f7; margin-bottom: 1px; }
+#nav-links a:hover { color: #fff; background: #000; }
+
+#content #title { display: block; text-decoration: none; border-bottom: 0; height: 74px; background: url('images/logo.png') no-repeat; border-bottom: 1px dotted #ddd; }
+#content h1, #content h2, #content h3 { margin-bottom: 0px; }
+#content h1 { color: #525252; line-height: 1em; }
+#content h2 { color: #585858; }
+#content h3 { color: #5A5A5A; }
+#content a:link, #content a:visited { color: #0098d1; text-decoration: none; border-bottom: 1px dotted #0098d1; }
+#content a:hover { color: #00baff; border-bottom: 1px dotted #00baff; }
+#content .meta p { font-size: 0.8em; color: #999; margin: 0; }
+#content .meta a:link, #content .meta a:visited { border-bottom: 0; }
+#content p { color: #555; text-align: left; line-height: 1.45em; }
+#content ul, #content ol { color: #555; text-align: left; line-height: 1.25em; }
+#content p strong { color: #333; }
+#content ul li strong, #content ol li strong { color: #333; }
+#content p img { padding: 10px; border: 0; }
+#content p img.border { border: 1px dotted #aaa; }
+#content tt { background: #eee; padding: 2px 4px; position: relative; top: -1px; font-size: 0.95em; font-family: monospace; }
+#content blockquote { background: url('images/quote.png') no-repeat; padding: 0px 43px; margin-left: 15px; color: #888; text-align: left; font-style: normal; }
+#content pre { background: #333; color: #d9d9d9; padding: 9px; padding-left: 20px; font-family: monospace; font-size: 0.95em; overflow-x: auto; }
+#content pre strong { font-weight: normal; color: #fff; }
+#content pre a:link, #content pre a:visited { border: 0; }
+#copyright { margin-top: 10px; padding-top: 25px; font-size: 0.7em; text-align: center; color: #999; border-top: 1px solid #eee; }
+#copyright small { color: #aaa; font-style: oblique; }
+
+#nav h2 { font-size: 1em; margin: 0; padding: 0; width: 260px; padding: 6px 15px; text-decoration: none; background: #333; color: #f7f7f7; font-weight: normal; position: relative; left: -5px; }
+#nav p { padding: 6px 15px; color: #666; margin: 0; }
+#nav strong { font-weight: 500; color: #333; }
+#nav .section { width: 285px; padding-bottom: 10px; font-size: 0.9em; }
+#nav a:link, #nav a:visited { text-decoration: none; color: #0098d1; border: 0; }
+#nav .section ul { list-style: none; padding: 12px; padding-top: 0; margin: 0; margin-top: 10px; }
+#nav .section li { padding: 6px 12px; background: #f5f5f5; margin: 0; margin-bottom: 12px; }
+#nav .section.articles li { padding: 0; display: inline; }
+#nav .section li a:link, #nav .section li a:visited { display: block; background: #f5f5f5; margin-bottom: 10px; padding: 6px 12px; text-decoration: none; color: #0098d1; border: 0; }
+#nav .section li a:hover { background: #333; }
+#nav .section.articles h2 a.rss{ font-size: 0.9em; }
+#nav .section.articles h2 .title { float: left; display: block; width: 100px; height: 28px; }
+#nav .section.articles h2 a.rss:link, #nav .section.articles h2 a.rss:visited { float: right; text-align: center; width: 55px; display: block; background: #0098d1; padding: 3px 5px; color: #fff; position: relative; top: -3px; left: 12px; }
+#nav .section.articles h2 a.rss:hover { background: #20b8f1; }
+#nav .section.twitter h2 a.follow { font-size: 0.9em; }
+#nav .section.twitter h2 .title { float: left; display: block; width: 100px; height: 28px; }
+#nav .section.twitter h2 a.follow:link, #nav .section.twitter h2 a.follow:visited { float: right; text-align: center; width: 55px; display: block; background: #0098d1; padding: 3px 5px; color: #fff; position: relative; top: -3px; left: 12px; }
+#nav .section.twitter h2 a.follow:hover { background: #20b8f1; }
+#nav .section.twitter ul a { display: inline; background: transparent; padding: 0; }
+#nav .section.twitter li { font-size: 0.9em; }
+#nav .section.twitter li small { font-size: 0.8em; color: #aaa; }
+#nav .section.twitter li small a:link, #nav .section.twitter li small a:visited { color: #36a7d1; }
+#nav .section.twitter li small a:hover { color: #0098d1; }
+#nav .section.ads { margin: 0 auto; width: 180px; }
+
+#nav .section.about img { padding-left: 10px; }
+
+#content pre.applescript { font-family: Verdana, sans-serif; font-size: 12px; background: #fff; }
+#content pre.applescript .recword { color: #320BFF; }
+#content pre.applescript .var { color: #1D8C12; }
+#content pre.applescript .keyword { color: #4200FF; font-weight: bold; }
+#content p.update { border-top: 1px solid #ddd; margin-top: 1.5em; padding-top: 1.5em; }
+#content code.dark, #content pre.dark { background: #222; color: #eee; border-left-color: #444; }
+
+.alignleft { float: left; }
+.alignright { float: right; }
+#content .navigation { margin: 15px 0; }
+#content .navigation a:link, #content .navigation a:visited { font-size: 0.8em; display: block; border: 1px solid #0098d1; padding: 4px; width: 40px; text-align: center; background: #fff; }
+
+#content .articles { padding: 0; margin: 15px 0; list-style: none; margin-bottom: 25px; }
+#content .articles li { margin-top: 5px; }
+#content .articles li small { color: #bbb; font-size: 0.7em; }
+#content .articles li a:link, #content .articles li a:visited { border-bottom-style: solid; }
+#content .writings { padding: 4px 0px; background: #fff; margin-top: 15px; }
+#content .writings h1 { padding-top: 0; margin-top: 5px; }
+#content .latest h2 { margin-bottom: 5px; border: 1px dashed #0098d1; padding: 12px; }
+#content .latest h2 a { border: 0; }
+
+.twitterapp.loading { min-height: 40px; background: url('images/loading.gif') no-repeat; background-position: center center; }
+
+#wrapper.wide { background: #f9f9f9; }
+#wrapper.wide #nav { background: #f9f9f9; width: 455px; }
+#wrapper.wide #content { width: 465px; }
+#wrapper.wide #nav-links { width: 429px; }
+#wrapper.wide #nav h2 { width: 425px; left: 0; }
+#wrapper.wide #nav .section { width: 455px; }
+#wrapper.wide #nav .section.about p { height: 70px; }
+#wrapper.wide #nav .section.twitter li { padding-left: 0; font-size: 1.1em; background: transparent; }
+
+.wp-caption-text { padding-top: 0; margin-top: 0; color: #999; font-size: 0.9em; font-style: italic; width: 600px; margin: 0 10px; }
+.note { border-right: #ccc 1px solid; padding-right: 7px; border-top: #ccc 1px solid; padding-left: 7px; font-size: 0.8em; background: #eee; padding-bottom: 7px; border-left: #ccc 1px solid; padding-top: 7px; border-bottom: #ccc 1px solid; }
+
+/* Github Ruby syntax colours */
+#content pre.ruby { background: #fff; color: #111; border: 1px solid #ccc; }
+#content pre strong { font-weight: bold; color: #000; }
+pre.ruby .keyword { font-weight: bold; }
+pre.ruby .class { color:#445588;
+ font-weight: bold; }
+pre.ruby .method { color:#990000;
+ font-weight:bold; }
+pre.ruby .constant { color: #177F80; }
+pre.ruby .global { color: #177F80; }
+pre.ruby .punct { color: #333; }
+pre.ruby .attribute { color: #0086B3; }
+pre.ruby .comment { color: #999988;
+ font-style: italic; }
+pre.ruby .regex { color: #159828; }
+pre.ruby .string { color:#D81745; }
+pre.ruby .expr { color:#D81745; }
+pre.ruby .number { color: #1C9898; }
+pre.ruby .symbol { color: #960B73; }
+pre.ruby .pre-strong { font-weight: bold; }
+pre.ruby .escape { }
+pre.ruby .ident { }
+
+#content .multipage { border: 1px solid #bbb; padding: 12px; background: #e9e9e9; }
+
+#content .gist-data pre { color: #000; font-family: 'Bitstream Vera Sans Mono','Courier', monospace; font-size: 0.8em; }
+#content .gist-meta { font-size: 0.9em; font-family: sans-serif; }
+#content .gist-meta a:link, #content .gist-meta a:visited { text-decoration: none; border: 0; }
+
+hr { border-collapse: collapse; border: 0; border-top: 1px dotted #aaa; height: 1px; }
+#content #disqus_thread a:link, #content #disqus_thread a:visited { border: 0; }
+#content a:link.noborder, #content a:visited.noborder { border: 0; }
+
+#content .talktome { padding: 6px 12px; border: 1px solid #ee8; background: #ffc; -moz-border-radius: 4px; -webkit-border-radius: 4px; color: #333; margin: 15px 0; margin-top: 30px; }
+#content .talktome a:link, #content .talktome a:visited { border: 0; }
+
+#content .storycontent li { margin-bottom: 12px; }
+#content .storycontent li:last-child { margin-bottom: 0px; }
+
+/* highlight.js */
+pre .shebang, pre .comment, pre .template_comment, pre .javadoc { color: #aaa; }
+pre .keyword, pre .tag, pre .ruby .function .keyword, pre .keymethods { color: #96CBFE; }
+pre .function .keyword, pre .sub .keyword, pre .method, pre .list .title { color: #ccf; }
+pre .string, pre .attribute .value, pre .cdata, pre .filter .argument, pre .attr_selector, pre .apache .cbracket, pre .date { color: #A8FF60; }
+pre .subst { color: #DAEFA3; }
+pre .regexp { color: #E9C062; }
+pre .class .title, pre .constant, pre .inheritance .parent, pre .sub .identifier, pre .pi, pre .decorator, pre .ini .title { color: #bef; }
+pre .function .title, pre .ftitle { color: #fff; font-weight: bold; }
+pre .symbol, pre .symbol .string, pre .symbol .keymethods, pre .symbol .keyword { color: #ff5546; }
+pre .smalltalk .class, pre .javadoctag, pre .phpdoc, pre .preprocessor, pre.yardoctag { color: #FFFFB6; }
+pre .number, pre .variable, pre .vbscript, pre .literal { color: #abf; }
+pre .css .keyword { color: #96CBFE; }
+pre .css .rule .keyword, pre .css .id { color: #FFFFB6; }
+pre .css .class { color: #FFF; }
+pre .hexcolor { color: #C6C5FE; }
+pre .number { color:#FF73FD; } \ No newline at end of file
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter.js b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter.js
new file mode 100644
index 0000000..35fa28c
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter.js
@@ -0,0 +1,52 @@
+function startTwitter() {
+ $('.twitterapp').addClass('loading');
+ $("<ul/>").addClass('twitterapplist').appendTo('.twitterapp');
+ $.getJSON("/twitterfeed.html",
+ function(data) {
+ $('.twitterapp').removeClass('loading');
+ var num = 0;
+ $.each(data, function(i, item) {
+ if (item.text[0] == "@") return;
+ $("<li/>").html(twitterStatus(item)).appendTo(".twitterapplist");
+ if (num++ == 5) return false;
+ });
+ if ($('#content').height() < $('#nav').height()) {
+ if (!$('#wrapper').hasClass('wide')) {
+ $('#wrapper').css('background', '#fff');
+ }
+ }
+ });
+
+
+}
+
+function twitterStatus(item) {
+ var text = item.text;
+ text = text.replace(/(https?:\/\/[^ ,!;?]+)(?:[,.!;\)\]-](\s|$)|$)/g, "<a href='$1'>$1</a>$2");
+ text = text.replace(/#([^ ,!;?]+)\b/g, "#<a href='http://search.twitter.com/search?q=%23$1'>$1</a>");
+ text = text.replace(/@([^ ,!;?]+)\b/g, "@<a href='http://twitter.com/$1'>$1</a>");
+ text = text + " <small>" + twitterSince(item) + " | <a href='http://twitter.com/lsegal/status/" + item.id + "'>link</a></small>";
+ return text;
+}
+
+function twitterSince(item) {
+ var now = new Date();
+ var date = Date.parse(item.created_at);
+ var diff = parseInt(now.getTime() / 1000) - parseInt(date / 1000);
+ var time = "";
+ if (diff >= 86400) {
+ time = parseInt(diff / 86400.0) + "d";
+ }
+ else if (diff >= 3600) {
+ time = parseInt(diff / 3600.0) + "h";
+ }
+ else if (diff >= 60) {
+ time = parseInt(diff / 60.0) + "m";
+ }
+ else {
+ time = diff + "s";
+ }
+ return time + " ago";
+}
+
+$(startTwitter);
diff --git a/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter_icon.jpg b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter_icon.jpg
new file mode 100644
index 0000000..7344755
--- /dev/null
+++ b/old/toy/doc/Writing Your Own Toy Compiler Using Flex, Bison and LLVM (gnuu.org)_files/twitter_icon.jpg
Binary files differ
diff --git a/old/toy/doc/os-createcompilerllvm1.txt b/old/toy/doc/os-createcompilerllvm1.txt
new file mode 100644
index 0000000..0be1eb0
--- /dev/null
+++ b/old/toy/doc/os-createcompilerllvm1.txt
@@ -0,0 +1,1193 @@
+
+ [1]Skip to main content
+ * [2]dW
+ * [3]Sign in (or register)
+ * [4]English
+ * [5][userid]
+ * [6]IBM
+
+ IBM ID: ____________________
+ Password: ____________________
+
+ [_] Keep me signed in.
+
+ By clicking Submit, you agree to the [7]developerWorks terms of use.
+ Submit
+ * [8]Need an IBM ID?
+ * [9]Forgot your IBM ID?
+
+ * [10]Forgot your password?
+ * [11]Change your password
+
+ The first time you sign into developerWorks, a profile is created for
+ you. Select information in your profile (name, country/region, and
+ company) is displayed to the public and will accompany any content you
+ post. You may update your IBM account at any time.
+
+ All information submitted is secure.
+ * [12]Close [x]
+
+ The first time you sign in to developerWorks, a profile is created for
+ you, so you need to choose a display name. Your display name
+ accompanies the content you post on developerworks.
+
+ Please choose a display name between 3-31 characters. Your display name
+ must be unique in the developerWorks community and should not be your
+ email address for privacy reasons.
+ Display name: _________________________
+
+ By clicking Submit, you agree to the [13]developerWorks terms of use.
+ Submit
+
+ All information submitted is secure.
+ * [14]Close [x]
+
+My developerWorks:
+
+ * [15]My home
+ * [16]My profile
+ * [17]My communities
+ * [18]Settings
+
+My notifications:
+
+ * [19]{[num_notify] new notifications}([num_notify] new notification)
+ * [20]{[num_invite] network requests}([num_invite] network request)
+
+ * [21]Sign out
+
+ * [22]Close [x]
+
+Select a language:
+
+ * [23]English
+ * [24]­
+ * [25]¥¬
+ * [26]Russkij
+
+ * [27]Português (Brasil)
+ * [28]Español
+ * [29]Vie>-.t
+
+ * [30]Close [x]
+
+ * [31]IBM home
+ * [32]Industries & solutions
+ * [33]Services
+ * [34]Products
+ * [35]Support & downloads
+
+ * [36]Product information
+ * [37]Redbooks
+ * [38]Software
+ * [39]Software services
+
+ * [40]Close [x]
+
+ * [41]developerWorks®
+
+ * [42]Technical topics
+ * [43]Evaluation software
+ * [44]Community
+ * [45]Events
+
+ Search developerWorks ____________________ Search
+
+[46]Technical topics
+
+ * [47]Agile transformation
+ * [48]AIX and UNIX
+ * [49]Big data
+ * [50]Business analytics
+ * [51]Business process management
+
+ * [52]Cloud computing
+ * [53]Commerce
+ * [54]IBM i
+ * [55]Industries
+ * [56]Information management
+
+ * [57]Java technology
+ * [58]Linux
+ * [59]Lotus (collaboration)
+ * [60]Mobile development
+ * [61]Open source
+
+ * [62]Rational
+ * [63]Security
+ * [64]Tivoli (service management)
+ * [65]Web development
+ * [66]WebSphere
+
+ * [67]Technical library
+ * [68]Products A to Z
+
+ * [69]Close [x]
+
+[70]Evaluation software
+
+ * [71]Business analytics
+ * [72]Information management
+ * [73]Lotus (collaboration)
+ * [74]Rational
+
+ * [75]Tivoli (service management)
+ * [76]WebSphere
+ * [77]More IBM products (Mobile, PureSystems, Security...)
+
+ * [78]Close [x]
+
+[79]Community
+
+ * [80]My home
+ * [81]Profiles
+ * [82]Communities
+
+ * [83]Blogs
+ * [84]Forums
+ * [85]Wikis
+
+ * [86]Activities
+ * [87]Podcasts
+ * [88]IBM Champion program
+
+ * [89]Close [x]
+
+[90]Events
+
+ * [91]Webcasts
+ * [92]Find events (webcasts, conferences...)
+
+ * [93]Close [x]
+
+ * [94]developerWorks
+ * [95]Technical topics
+ * [96]Open source
+ * [97]Technical library
+
+Create a working compiler with the LLVM framework, Part 1
+
+ Build a custom compiler with LLVM and its intermediate representation
+ [98]Arpan Sen, Author, Independent
+ Arpan Sen is a lead engineer working on the development of software in
+ the electronic design automation industry. He has worked on several
+ flavors of UNIX, including Solaris, SunOS, HP-UX, and IRIX, as well as
+ Linux and Microsoft Windows for several years. He takes a keen interest
+ in software performance-optimization techniques, graph theory, and
+ parallel computing. Arpan holds a post-graduate degree in software
+ systems.
+
+ Summary: The LLVM compiler infrastructure provides a powerful way to
+ optimize your applications regardless of the programming language you
+ use. Learn the basics of the LLVM in this first article of a two-part
+ series. Building a custom compiler just got easier!
+
+ 19 Jun 2012 - Added links to Part 2 of this article to sidebars in the
+ [99]introduction and [100]Conclusion, and in [101]Resources.
+
+ Date: 19 Jun 2012 (Published 05 Jun 2012)
+ Level: Intermediate
+ PDF: [102]A4 and Letter (275 KB | 13 pages)[103]Get Adobe® Reader®
+ Also available in: [104]Chinese [105]Russian [106]Japanese
+ Activity: 63698 views
+ Comments:
+
+ The LLVM (formerly the Low Level Virtual Machine) is an extremely
+ powerful compiler infrastructure framework designed for compile-time,
+ link-time, and run time optimizations of programs written in your
+ favorite programming language. LLVM works on several different
+ platforms, and its primary claim to fame is generating code that runs
+ fast.
+
+Other articles in this series
+
+ View more articles in the [107]Create a working compiler with the LLVM
+ framework series.
+
+ The LLVM framework is built around a well-documented intermediate
+ representation (IR) of code. This article--the first in a two-part
+ series--delves into the basics of the LLVM IR and some of its
+ subtleties. From there, you will build a code generator that can
+ automate the work of generating the LLVM IR for you. Having an LLVM IR
+ generator means that all you need is a front end for your favorite
+ language to plug into, and you have a full flow (front-end parser + IR
+ generator + LLVM back end). Creating a custom compiler just got
+ simplified.
+
+ Getting started with the LLVM
+
+ Before you start, you must have the LLVM compiled on your development
+ computer (see [108]Resources for a link). The examples in this article
+ are based on LLVM version 3.0. The two most important tools for
+ post-build and installation of LLVM code are llc and lli.
+
+ llc and lli
+
+ Because LLVM is a virtual machine (VM), it likely should have its own
+ intermediate byte code representation, right? Ultimately, you need to
+ compile LLVM byte code into your platform-specific assembly language.
+ Then you can run the assembly code through a native assembler and
+ linker to generate executables, shared libraries, and so on. You use
+ llc to convert LLVM byte code to platform-specific assembly code (see
+ [109]Resources for a link to more information about this tool). For
+ directly executing portions of LLVM byte code, don't wait until the
+ native executable crashes to figure out that you have a bug or two in
+ your program. This is where lli comes in handy, as it can directly
+ execute the byte code. lli performs this feat either through an
+ interpreter or by using a just-in-time (JIT) compiler under the hood.
+ See [110]Resources for a link to more information about lli.
+
+ llvm-gcc
+
+ llvm-gcc is a modified version of the GNU Compiler Collection (gcc)
+ that can generate LLVM byte code when run with the -S -emit-llvm
+ options. You can then use lli to execute this generated byte code (also
+ known as LLVM assembly). For more information about llvm-gcc, see
+ [111]Resources. If you don't have llvm-gcc preinstalled on your system,
+ you should be able to build it from sources; see [112]Resources for a
+ link to the step-by-step guide.
+ __________________________________________________________________
+
+ [113]Back to top
+
+ Hello World with LLVM
+
+ To better understand LLVM, you have to learn LLVM IR and its
+ idiosyncrasies. This process akin to learning yet another programming
+ language. But if you have been through C and C++ and their quirks,
+ there shouldn't be much to deter you in the LLVM IR. [114]Listing 1
+ shows your first program, which prints "Hello World" in the console
+ output. To compile this code, you use llvm-gcc.
+ Listing 1. The familiar-looking Hello World program
+
+#include <stdio.h>
+int main( )
+{
+ printf("Hello World!\n");
+}
+
+ To compile the code, enter this command:
+Tintin.local# llvm-gcc helloworld.cpp -S -emit-llvm
+
+ After compilation, llvm-gcc generates the file helloworld.s, which you
+ can execute using lli to print the message to console. The lli usage
+ is:
+Tintin.local# lli helloworld.s
+Hello, World
+
+ Now, take a first look at the LLVM assembly. [115]Listing 2 shows the
+ code.
+ Listing 2. LLVM byte code for the Hello World program
+
+@.str = private constant [13 x i8] c"Hello World!\00", align 1 ;
+
+define i32 @main() ssp {
+entry:
+ %retval = alloca i32
+ %0 = alloca i32
+ %"alloca point" = bitcast i32 0 to i32
+ %1 = call i32 @puts(i8* getelementptr inbounds ([13 x i8]* @.str, i64 0, i64 0
+))
+ store i32 0, i32* %0, align 4
+ %2 = load i32* %0, align 4
+ store i32 %2, i32* %retval, align 4
+ br label %return
+return:
+ %retval1 = load i32* %retval
+ ret i32 %retval1
+}
+
+declare i32 @puts(i8*)
+ __________________________________________________________________
+
+ [116]Back to top
+
+ Understanding the LLVM IR
+
+ The LLVM comes with a detailed assembly language representation (see
+ [117]Resources for a link). Here are the must-knows before you try to
+ craft your own version of the Hello World program discussed earlier:
+ * Comments in LLVM assembly begin with a semicolon (;) and continue
+ to the end of the line.
+ * Global identifiers begin with the at (@) character. All function
+ names and global variables must begin with @, as well.
+ * Local identifiers in the LLVM begin with a percent symbol (%). The
+ typical regular expression for identifiers is
+ [%@][a-zA-Z$._][a-zA-Z$._0-9]*.
+ * The LLVM has a strong type system, and the same is counted among
+ its most important features. The LLVM defines an integer type as
+ iN, where N is the number of bits the integer will occupy. You can
+ specify any bit width between 1 and 223- 1.
+ * You declare a vector or array type as [no. of elements X size of
+ each element]. For the string "Hello World!" this makes the type
+ [13 x i8], assuming that each character is 1 byte and factoring in
+ 1 extra byte for the NULL character.
+ * You declare a global string constant for the hello-world string as
+ follows: @hello = constant [13 x i8] c"Hello World!\00". Use the
+ constant keyword to declare a constant followed by the type and the
+ value. The type has already been discussed, so let's look at the
+ value: You begin by using c followed by the entire string in double
+ quotation marks, including \0 and ending with 0. Unfortunately, the
+ LLVM documentation does not provide any explanation of why a string
+ needs to be declared with the c prefix and include both a NULL
+ character and 0 at the end. See [118]Resources for a link to the
+ grammar file, if you're interested in exploring more LLVM quirks.
+ * The LLVM lets you declare and define functions. Instead of going
+ through the entire feature list of an LLVM function, I concentrate
+ on the bare bones. Begin with the define keyword followed by the
+ return type, and then the function name. A simple definition of
+ main that returns a 32-bit integer similar to: define i32 @main() {
+ ; some LLVM assembly code that returns i32 }.
+ * Function declarations, like definitions, have a lot of meat to
+ them. Here's the simplest declaration of a puts method, which is
+ the LLVM equivalent of printf: declare i32 puts(i8*). You begin the
+ declaration with the declare keyword followed by the return type,
+ the function name, and an optional list of arguments to the
+ function. The declaration must be in the global scope.
+ * Each function ends with a return statement. There are two forms of
+ return statement: ret <type> <value> or ret void. For your simple
+ main routine, ret i32 0 suffices.
+ * Use call <function return type> <function name> <optional function
+ arguments> to call a function. Note that each function argument
+ must be preceded by its type. A function test that returns an
+ integer of 6 bits and accepts an integer of 36 bits has the syntax:
+ call i6 @test( i36 %arg1 ).
+
+ That's it for a start. You need to define a main routine, a constant to
+ hold the string, and a declaration of the puts method that handles the
+ actual printing. [119]Listing 3 shows the first attempt.
+ Listing 3. First attempt to create a hand-crafted Hello World program
+
+declare i32 @puts(i8*)
+@global_str = constant [13 x i8] c"Hello World!\00"
+define i32 @main {
+ call i32 @puts( [13 x i8] @global_str )
+ ret i32 0
+}
+
+ And here's the log from lli:
+lli: test.s:5:29: error: global variable reference must have pointer type
+ call i32 @puts( [13 x i8] @global_str )
+ ^
+
+ Oops, that didn't work as expected. What just happened? The LLVM, as
+ mentioned earlier, has a powerful type system. Because puts was
+ expecting a pointer to i8 and you passed a vector of i8, lli was quick
+ to point out the error. The obvious fix to this problem, coming from a
+ C programming background, is typecasting. And that brings you to the
+ LLVM instruction getelementptr. Note that you must modify the puts call
+ in [120]Listing 3 to something like call i32 @puts(i8* %t), where %t is
+ of type i8* and is the result of the typecast from [13 x i8] to i8*.
+ (See [121]Resources for a link to a detailed description of
+ getelementptr.) Before going any farther, [122]Listing 4 provides the
+ code that works.
+ Listing 4. Using getelementptr to correctly typecast to a pointer
+
+declare i32 @puts (i8*)
+@global_str = constant [13 x i8] c"Hello World!\00"
+
+define i32 @main() {
+ %temp = getelementptr [13 x i8]* @global_str, i64 0, i64 0
+ call i32 @puts(i8* %temp)
+ ret i32 0
+}
+
+ The first argument to getelementptr is the pointer to the global string
+ variable. The first index, i64 0, is required to step over the pointer
+ to the global variable. Because the first argument to the getelementptr
+ instruction must always be a value of type pointer, the first index
+ steps through that pointer. A value of 0 means 0 elements offset from
+ that pointer. My development computer is running 64-bit Linux®, so the
+ pointer is 8 bytes. The second index, i64 0, is used to select the 0th
+ element of the string, which is supplied as the argument to puts.
+ __________________________________________________________________
+
+ [123]Back to top
+
+ Creating a custom LLVM IR code generator
+
+ Understanding the LLVM IR is fine, but you need an automated
+ code-generation system that dumps LLVM assembly. Thankfully, LLVM does
+ have enough application programming interface (API) support to see you
+ through this effort (see [124]Resources for a link to the programmer's
+ manual). Look for the file LLVMContext.h on your development computer;
+ if that file is missing, something is probably wrong with the way you
+ installed the LLVM.
+
+ Now, let's create a program that generates LLVM IR for the Hello World
+ program discussed earlier. The program won't deal with the entire LLVM
+ API here, but the code samples that follow should prove that a fair bit
+ of the LLVM API is intuitive and easy to use.
+
+ Linking against LLVM code
+
+ The LLVM comes with a nifty tool called llvm-config (see
+ [125]Resources). Run llvm-config -cxxflags to get the compile flags
+ that need to be passed to g++, llvm-config -ldflags for the linker
+ options, and llvm-config -libs to link against the right LLVM
+ libraries. In the sample in [126]Listing 5, all the options need to be
+ passed to g++.
+ Listing 5. Using llvm-config to build code with the LLVM API
+
+tintin# llvm-config --cxxflags --ldflags --libs \
+-I/usr/include -DNDEBUG -D_GNU_SOURCE \
+-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS \
+-D__STDC_LIMIT_MACROS -O3 -fno-exceptions -fno-rtti -fno-common \
+-Woverloaded-virtual -Wcast-qual \
+-L/usr/lib -lpthread -lm \
+-lLLVMXCoreCodeGen -lLLVMTableGen -lLLVMSystemZCodeGen \
+-lLLVMSparcCodeGen -lLLVMPTXCodeGen \
+-lLLVMPowerPCCodeGen -lLLVMMSP430CodeGen -lLLVMMipsCodeGen \
+-lLLVMMCJIT -lLLVMRuntimeDyld \
+-lLLVMObject -lLLVMMCDisassembler -lLLVMXCoreDesc -lLLVMXCoreInfo \
+-lLLVMSystemZDesc -lLLVMSystemZInfo \
+-lLLVMSparcDesc -lLLVMSparcInfo -lLLVMPowerPCDesc -lLLVMPowerPCInfo \
+-lLLVMPowerPCAsmPrinter \
+-lLLVMPTXDesc -lLLVMPTXInfo -lLLVMPTXAsmPrinter -lLLVMMipsDesc \
+-lLLVMMipsInfo -lLLVMMipsAsmPrinter \
+-lLLVMMSP430Desc -lLLVMMSP430Info -lLLVMMSP430AsmPrinter \
+-lLLVMMBlazeDisassembler -lLLVMMBlazeAsmParser \
+-lLLVMMBlazeCodeGen -lLLVMMBlazeDesc -lLLVMMBlazeAsmPrinter \
+-lLLVMMBlazeInfo -lLLVMLinker -lLLVMipo \
+-lLLVMInterpreter -lLLVMInstrumentation -lLLVMJIT -lLLVMExecutionEngine \
+-lLLVMDebugInfo -lLLVMCppBackend \
+-lLLVMCppBackendInfo -lLLVMCellSPUCodeGen -lLLVMCellSPUDesc \
+-lLLVMCellSPUInfo -lLLVMCBackend \
+-lLLVMCBackendInfo -lLLVMBlackfinCodeGen -lLLVMBlackfinDesc \
+-lLLVMBlackfinInfo -lLLVMBitWriter \
+-lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen \
+-lLLVMX86Desc -lLLVMX86AsmPrinter -lLLVMX86Utils \
+-lLLVMX86Info -lLLVMAsmParser -lLLVMARMDisassembler -lLLVMARMAsmParser \
+-lLLVMARMCodeGen -lLLVMARMDesc \
+-lLLVMARMAsmPrinter -lLLVMARMInfo -lLLVMArchive -lLLVMBitReader \
+-lLLVMAlphaCodeGen -lLLVMSelectionDAG \
+-lLLVMAsmPrinter -lLLVMMCParser -lLLVMCodeGen -lLLVMScalarOpts \
+-lLLVMInstCombine -lLLVMTransformUtils \
+-lLLVMipa -lLLVMAnalysis -lLLVMTarget -lLLVMCore -lLLVMAlphaDesc \
+-lLLVMAlphaInfo -lLLVMMC -lLLVMSupport
+
+ LLVM modules, contexts, and more
+
+ An LLVM module class is the top-level container for all other LLVM IR
+ objects. An LLVM module class can contain a list of global variables,
+ functions, other modules on which this module depends, symbol tables,
+ and more. Here's the constructor for an LLVM module:
+explicit Module(StringRef ModuleID, LLVMContext& C);
+
+ You must begin your program by creating an LLVM module. The first
+ argument is the name of the module and can be any dummy string. The
+ second argument is something called LLVMContext. The LLVMContext class
+ is somewhat opaque, but it's enough to understand that it provides a
+ context in which variables and so on are created. This class becomes
+ important in the context of multiple threads, where you might want to
+ create a local context per thread, and each thread runs completely
+ independently of any other's context. For now, use the default global
+ context handle that the LLVM provides. Here's the code to create a
+ module:
+llvm::LLVMContext& context = llvm::getGlobalContext();
+
+llvm::Module* module = new llvm::Module("top", context);
+
+ The next important class to learn is the one that actually provides the
+ API to create LLVM instructions and insert them into basic blocks: the
+ IRBuilder class. IRBuilder comes with a lot of bells and whistles, but
+ I chose the simplest possible way to construct one--by passing the
+ global context to it with the code:
+llvm::LLVMContext& context = llvm::getGlobalContext();
+
+llvm::Module* module = new llvm::Module("top", context);
+
+llvm::IRBuilder<> builder(context);
+
+ When the LLVM object model is ready, you can dump its contents by
+ calling the module's dump method. [127]Listing 6 shows the code.
+ Listing 6. Creating a dummy module
+
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/IRBuilder.h"
+
+int main()
+{
+ llvm::LLVMContext& context = llvm::getGlobalContext();
+ llvm::Module* module = new llvm::Module("top", context);
+ llvm::IRBuilder<> builder(context);
+
+ module->dump( );
+}
+
+ After running the code in [128]Listing 6, this prints to the console:
+; ModuleID = 'top'
+
+ You need to create the main method next. LLVM provides the classes
+ llvm::Function to create a function and llvm::FunctionType to associate
+ a return type for the function. Also, remember that the main method
+ must be a part of the module. [129]Listing 7 shows the code.
+ Listing 7. Adding the main method to the top module
+
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/IRBuilder.h"
+
+int main()
+{
+ llvm::LLVMContext& context = llvm::getGlobalContext();
+ llvm::Module *module = new llvm::Module("top", context);
+ llvm::IRBuilder<> builder(context);
+
+ llvm::FunctionType *funcType =
+ llvm::FunctionType::get(builder.getInt32Ty(), false);
+ llvm::Function *mainFunc =
+ llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main",
+module);
+
+ module->dump( );
+}
+
+ Note that you wanted main to return void, which is why you called
+ builder.getVoidTy(); if main returned i32, the call would be
+ builder.getInt32Ty(). After compiling and running the code in
+ [130]Listing 7, the result is:
+; ModuleID = 'top'
+declare void @main()
+
+ You have not yet defined the set of instructions that main is supposed
+ to execute. For that, you must define a basic block and associate it
+ with the main method. A basic block is a collection of instructions in
+ the LLVM IR that has the option of defining a label (akin to C labels)
+ as part of its constructor. The builder.setInsertPoint tells the LLVM
+ engine where to insert the instructions next. [131]Listing 8 shows the
+ code.
+ Listing 8. Adding a basic block to main
+
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/IRBuilder.h"
+
+int main()
+{
+ llvm::LLVMContext& context = llvm::getGlobalContext();
+ llvm::Module *module = new llvm::Module("top", context);
+ llvm::IRBuilder<> builder(context);
+
+ llvm::FunctionType *funcType =
+ llvm::FunctionType::get(builder.getInt32Ty(), false);
+ llvm::Function *mainFunc =
+ llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main",
+module);
+
+ llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entrypoint", main
+Func);
+ builder.SetInsertPoint(entry);
+
+ module->dump( );
+}
+
+ Here's the output of [132]Listing 8. Note that because the basic block
+ for main is now defined, the LLVM dump now treats main as a method
+ definition, not a declaration. Cool stuff!
+; ModuleID = 'top'
+define void @main() {
+entrypoint:
+}
+
+ Now, add the global hello-world string to the code. [133]Listing 9
+ shows the code.
+ Listing 9. Adding the global string to the LLVM module
+
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/IRBuilder.h"
+
+int main()
+{
+ llvm::LLVMContext& context = llvm::getGlobalContext();
+ llvm::Module *module = new llvm::Module("top", context);
+ llvm::IRBuilder<> builder(context);
+
+ llvm::FunctionType *funcType =
+ llvm::FunctionType::get(builder.getVoidTy(), false);
+ llvm::Function *mainFunc =
+ llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main",
+module);
+
+ llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entrypoint", main
+Func);
+ builder.SetInsertPoint(entry);
+
+ llvm::Value *helloWorld = builder.CreateGlobalStringPtr("hello world!\n");
+
+ module->dump( );
+}
+
+ In this output of [134]Listing 9, note how the LLVM engine dumps the
+ string:
+; ModuleID = 'top'
+@0 = internal unnamed_addr constant [14 x i8] c"hello world!\0A\00"
+define void @main() {
+entrypoint:
+}
+
+ All you need now is to declare the puts method and make a call to it.
+ To declare the puts method, you must create the appropriate
+ FunctionType*. From your original Hello World code, you know that puts
+ returns i32 and accepts i8* as the input argument. [135]Listing 10
+ shows the code to create the right type for puts.
+ Listing 10. Code to declare the puts method
+
+ std::vector<llvm::Type *> putsArgs;
+ putsArgs.push_back(builder.getInt8Ty()->getPointerTo());
+ llvm::ArrayRef<llvm::Type*> argsRef(putsArgs);
+
+ llvm::FunctionType *putsType =
+ llvm::FunctionType::get(builder.getInt32Ty(), argsRef, false);
+ llvm::Constant *putsFunc = module->getOrInsertFunction("puts", putsType);
+
+ The first argument to FunctionType::get is the return type; the second
+ argument is an LLVM::ArrayRef structure, and the last false indicates
+ that no variable number of arguments follows. The ArrayRef structure is
+ similar to a vector, except that it does not contain any underlying
+ data and is primarily used to wrap data blocks like arrays and vectors.
+ With this change, the output appears in [136]Listing 11.
+ Listing 11. Declaring the puts method
+
+; ModuleID = 'top'
+@0 = internal unnamed_addr constant [14 x i8] c"hello world!\0A\00"
+define void @main() {
+entrypoint:
+}
+declare i32 @puts(i8*)
+
+ All that remains is to call the puts method inside main and return from
+ main. The LLVM API takes care of the casting and all the rest: All you
+ need to call puts is to invoke builder.CreateCall. Finally, to create
+ the return statement, call builder.CreateRetVoid. [137]Listing 12
+ provides the complete working code.
+ Listing 12. The complete code to print Hello World
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/Support/IRBuilder.h"
+#include <vector>
+#include <string>
+
+int main()
+{
+ llvm::LLVMContext & context = llvm::getGlobalContext();
+ llvm::Module *module = new llvm::Module("asdf", context);
+ llvm::IRBuilder<> builder(context);
+
+ llvm::FunctionType *funcType = llvm::FunctionType::get(builder.getVoidTy(), fa
+lse);
+ llvm::Function *mainFunc =
+ llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main", mo
+dule);
+ llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entrypoint", main
+Func);
+ builder.SetInsertPoint(entry);
+
+ llvm::Value *helloWorld = builder.CreateGlobalStringPtr("hello world!\n");
+
+ std::vector<llvm::Type *> putsArgs;
+ putsArgs.push_back(builder.getInt8Ty()->getPointerTo());
+ llvm::ArrayRef<llvm::Type*> argsRef(putsArgs);
+
+ llvm::FunctionType *putsType =
+ llvm::FunctionType::get(builder.getInt32Ty(), argsRef, false);
+ llvm::Constant *putsFunc = module->getOrInsertFunction("puts", putsType);
+
+ builder.CreateCall(putsFunc, helloWorld);
+ builder.CreateRetVoid();
+ module->dump();
+}
+ __________________________________________________________________
+
+ [138]Back to top
+
+ Conclusion
+
+Other articles in this series
+
+ View more articles in the [139]Create a working compiler with the LLVM
+ framework series.
+
+ In this initial study of LLVM, you learned about LLVM tools like lli
+ and llvm-config, dug into LLVM intermediate code, and used the LLVM API
+ to generate the intermediate code for you. The second and final part of
+ this series will explore yet another task you can use the LLVM
+ for--adding an extra compilation pass with minimum effort.
+
+ Resources
+
+ Learn
+ * Move beyond the basics of the LLVM in [140]Create a working
+ compiler with the LLVM framework, Part 2: Use clang to preprocess
+ C/C++ code (Arpan Sen, developerWorks, June 2012). Put your
+ compiler to work as you use the clang API to preprocess C/C++ code
+ as the LLVM compiler series continues.
+ * Take the official [141]LLVM Tutorial for a great introduction to
+ LLVM.
+ * See [142]Chris Latner's chapter in The Architecture of Open Source
+ Applications for more information on the development of LLVM.
+ * Learn more about two important LLVM tools: [143]llc and [144]lli.
+ * Find more information about the llvm-gcc tool, and learn how to
+ build it from source with the step-by-step guide, [145]Building
+ llvm-gcc from Source.
+ * Read more about the LLVM assembly language in the [146]LLVM
+ Language Reference Manual.
+ * Check out its [147]grammar file, Log of /llvm/trunk/utils/llvm.grm,
+ for more information about the global string constant in LLVM.
+ * Learn more about the [148]getelementptr instruction in "The Often
+ Misunderstood GEP Instruction" document.
+ * Dig into the [149]LLVM Programmer's Manual, an indispensable
+ resource for the LLVM API.
+ * Read about the [150]llvm-config tool for printing LLVM compilation
+ options.
+ * The [151]Open Source developerWorks zone provides a wealth of
+ information on open source tools and using open source
+ technologies.
+ * In the [152]developerWorks Linux zone, find hundreds of [153]how-to
+ articles and tutorials, as well as downloads, discussion forums,
+ and a wealth of other resources for Linux developers and
+ administrators.
+ * [154]developerWorks Web development specializes in articles
+ covering various web-based solutions.
+ * Stay current with [155]developerWorks technical events and webcasts
+ focused on a variety of IBM products and IT industry topics.
+ * Attend a [156]free developerWorks Live! briefing to get up-to-speed
+ quickly on IBM products and tools, as well as IT industry trends.
+ * Watch [157]developerWorks on-demand demos ranging from product
+ installation and setup demos for beginners, to advanced
+ functionality for experienced developers.
+ * Follow [158]developerWorks on Twitter, or subscribe to a feed of
+ [159]Linux tweets on developerWorks.
+
+ Get products and technologies
+ * [160]Evaluate IBM products in the way that suits you best: Download
+ a product trial, try a product online, use a product in a cloud
+ environment, or spend a few hours in the [161]SOA Sandbox learning
+ how to implement Service Oriented Architecture efficiently.
+
+ Discuss
+ * Check out [162]developerWorks blogs and get involved in the
+ [163]developerWorks community.
+ * Get involved in the [164]developerWorks community. Connect with
+ other developerWorks users while exploring the developer-driven
+ blogs, forums, groups, and wikis.
+
+ About the author
+
+ Arpan Sen is a lead engineer working on the development of software in
+ the electronic design automation industry. He has worked on several
+ flavors of UNIX, including Solaris, SunOS, HP-UX, and IRIX, as well as
+ Linux and Microsoft Windows for several years. He takes a keen interest
+ in software performance-optimization techniques, graph theory, and
+ parallel computing. Arpan holds a post-graduate degree in software
+ systems.
+
+ [165]Close [x]
+ Report abuse help
+
+Report abuse
+
+ Thank you. This entry has been flagged for moderator attention.
+ __________________________________________________________________
+
+ [BUTTON Input] (not implemented)_____
+
+ [166]Close [x]
+ Report abuse help
+
+Report abuse
+
+ Report abuse submission failed. Please try again later.
+ __________________________________________________________________
+
+ [BUTTON Input] (not implemented)_____
+
+ [167]Close [x]
+
+developerWorks: Sign in
+
+ IBM ID: _________________________
+ [168]Need an IBM ID?
+ [169]Forgot your IBM ID?
+
+ Password: _________________________
+ [170]Forgot your password?
+ [171]Change your password
+
+ [_] Keep me signed in.
+
+ By clicking Submit, you agree to the [172]developerWorks terms of use.
+
+ Submit [BUTTON Input] (not implemented)______
+ __________________________________________________________________
+
+ The first time you sign into developerWorks, a profile is created for
+ you. Select information in your profile (name, country/region, and
+ company) is displayed to the public and will accompany any content you
+ post. You may update your IBM account at any time.
+
+ All information submitted is secure.
+
+ [173]Close [x]
+
+Choose your display name
+
+ The first time you sign in to developerWorks, a profile is created for
+ you, so you need to choose a display name. Your display name
+ accompanies the content you post on developerWorks.
+
+ Please choose a display name between 3-31 characters. Your display name
+ must be unique in the developerWorks community and should not be your
+ email address for privacy reasons.
+
+ Display name: _________________________(Must be between 3 - 31
+ characters.)
+
+ By clicking Submit, you agree to the [174]developerWorks terms of use.
+
+ Submit [BUTTON Input] (not implemented)______
+ __________________________________________________________________
+
+ All information submitted is secure.
+
+ Rate this article
+
+ Comments
+
+ [175]Back to top
+ static.content.url=http://www.ibm.com/developerworks/js/artrating/
+ SITE_ID=1
+ Zone=Open source, Linux
+ ArticleID=819206
+ ArticleTitle=Create a working compiler with the LLVM framework, Part 1
+ publish-date=06192012
+
+Table of contents
+
+ * [176]Getting started with the LLVM
+ * [177]Hello World with LLVM
+ * [178]Understanding the LLVM IR
+ * [179]Creating a custom LLVM IR code generator
+ * [180]Conclusion
+ * [181]Resources
+ * [182]About the author
+ * [183]Comments
+
+Dig deeper into Open source on developerWorks
+
+ * [184]Overview
+ * [185]New to Open source
+ * [186]Projects
+ * [187]Technical library (articles, tutorials, and more)
+ * [188]Forums
+ * [189]Events
+
+Try IBM PureSystems. No charge.
+
+ IBM PureSystems on a kaleideoscope background
+
+ Experience today!
+ __________________________________________________________________
+
+ [190]Get started with the cloud-based trial and pattern development
+ kit.
+
+Special offers
+
+ [191]On demand demos: An easy way to watch and learn
+
+ [192]Get recognized! W Author Program
+
+ [193]Cloud Computing resources for IT professionals
+ __________________________________________________________________
+
+ [194]Trial software offers
+ * [195]Print this page
+
+ * [196]Share this page
+ * [197]Follow developerWorks
+
+Share this page:
+
+ * [198]Facebook
+ * [199]LinkedIn
+ * [200]Twitter
+
+ * [201]Delicious
+ * [202]Digg
+ * [203]StumbleUpon
+
+ * [204]Email this page
+
+ * [205]Close [x]
+
+Follow developerWorks:
+
+ * [206]Facebook
+ * [207]Twitter
+
+ * [208]Close [x]
+
+ * [209]About
+ * [210]Help
+ * [211]Contact us
+ * [212]Submit content
+
+ * [213]Feeds
+
+ * [214]Report abuse
+ * [215]Terms of use
+ * [216]IBM privacy
+ * [217]IBM accessibility
+
+ * [218]Faculty
+ * [219]Students
+ * [220]Business Partners
+
+ IBM®
+
+Select a language:
+
+ * [221]English
+ * [222]­
+ * [223]¥¬
+ * [224]Russkij
+ * [225]Português (Brasil)
+ * [226]Español
+ * [227]Vie>-.t
+
+References
+
+ 1. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-content
+ 2. http://www.ibm.com/developerworks/
+ 3. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 4. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#SELECTLANG
+ 5. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 6. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 7. https://www.ibm.com/developerworks/community/terms/
+ 8. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 9. http://www.ibm.com/developerworks/dwwi/jsp/WSHelp.jsp?lang=en_US
+ 10. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 11. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 12. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 13. https://www.ibm.com/developerworks/community/terms/
+ 14. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 15. http://www.ibm.com/developerworks/community/homepage/web/updates/?lang=en
+ 16. http://www.ibm.com/developerworks/community/profiles/html/myProfileView.do?lang=en
+ 17. http://www.ibm.com/developerworks/community/groups/service/html/mycommunities?lang=en
+ 18. http://www.ibm.com/developerworks/community/news
+ 19. http://www.ibm.com/developerworks/community/homepage?lang=en
+ 20. http://www.ibm.com/developerworks/community/profiles/html/wc.do?action=in&requireAuth=true&widgetId=friends&lang=[lang]
+ 21. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 22. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 23. http://www.ibm.com/developerworks/
+ 24. http://www.ibm.com/developerworks/cn/
+ 25. http://www.ibm.com/developerworks/jp/
+ 26. http://www.ibm.com/developerworks/ru/
+ 27. http://www.ibm.com/developerworks/br/
+ 28. http://www.ibm.com/developerworks/ssa/
+ 29. http://www.ibm.com/developerworks/vn/
+ 30. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 31. http://www.ibm.com/
+ 32. http://www.ibm.com/solutions/
+ 33. http://www.ibm.com/technologyservices/
+ 34. http://www.ibm.com/products/
+ 35. http://www.ibm.com/support/
+ 36. http://www.ibm.com/support/publications/us/library/index.shtml
+ 37. http://www.ibm.com/redbooks/
+ 38. http://www.ibm.com/software/
+ 39. http://www.ibm.com/software/sw-services/
+ 40. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 41. http://www.ibm.com/developerworks/
+ 42. http://www.ibm.com/developerworks/topics/
+ 43. http://www.ibm.com/developerworks/downloads/
+ 44. http://www.ibm.com/developerworks/community/index.html
+ 45. http://www.ibm.com/developerworks/events/
+ 46. http://www.ibm.com/developerworks/topics/
+ 47. http://www.ibm.com/developerworks/agile/
+ 48. http://www.ibm.com/developerworks/aix/
+ 49. http://www.ibm.com/developerworks/bigdata/
+ 50. http://www.ibm.com/developerworks/analytics/
+ 51. http://www.ibm.com/developerworks/bpm/
+ 52. http://www.ibm.com/developerworks/cloud/
+ 53. http://www.ibm.com/developerworks/commerce/
+ 54. http://www.ibm.com/developerworks/ibmi/
+ 55. http://www.ibm.com/developerworks/industry/
+ 56. http://www.ibm.com/developerworks/data/
+ 57. http://www.ibm.com/developerworks/java/
+ 58. http://www.ibm.com/developerworks/linux/
+ 59. http://www.ibm.com/developerworks/lotus/
+ 60. http://www.ibm.com/developerworks/mobile/
+ 61. http://www.ibm.com/developerworks/opensource/
+ 62. http://www.ibm.com/developerworks/rational/
+ 63. http://www.ibm.com/developerworks/security/
+ 64. http://www.ibm.com/developerworks/servicemanagement/
+ 65. http://www.ibm.com/developerworks/web/
+ 66. http://www.ibm.com/developerworks/websphere/
+ 67. http://www.ibm.com/developerworks/library/
+ 68. http://www.ibm.com/developerworks/products/
+ 69. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 70. http://www.ibm.com/developerworks/downloads/
+ 71. http://www.ibm.com/developerworks/downloads/#ba
+ 72. http://www.ibm.com/developerworks/downloads/#data
+ 73. http://www.ibm.com/developerworks/downloads/#lotus
+ 74. http://www.ibm.com/developerworks/downloads/#rational
+ 75. http://www.ibm.com/developerworks/downloads/#tivoli
+ 76. http://www.ibm.com/developerworks/downloads/#websphere
+ 77. http://www.ibm.com/developerworks/downloads/#more
+ 78. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 79. http://www.ibm.com/developerworks/community/index.html
+ 80. http://www.ibm.com/developerworks/community/homepage/?lang=en
+ 81. http://www.ibm.com/developerworks/community/profiles/?lang=en
+ 82. http://www.ibm.com/developerworks/community/groups/?lang=en
+ 83. http://www.ibm.com/developerworks/community/blogs/?lang=en
+ 84. http://www.ibm.com/developerworks/community/forums/?lang=en
+ 85. http://www.ibm.com/developerworks/community/wikis/?lang=en
+ 86. http://www.ibm.com/developerworks/community/activities/?lang=en
+ 87. https://www.ibm.com/developerworks/community/podcasts/?lang=en
+ 88. http://www.ibm.com/developerworks/champion/
+ 89. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 90. http://www.ibm.com/developerworks/events/
+ 91. http://www.ibm.com/developerworks/find/webcasts/
+ 92. http://www.ibm.com/developerworks/find/events/
+ 93. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 94. http://www.ibm.com/developerworks/
+ 95. http://www.ibm.com/developerworks/topics/
+ 96. http://www.ibm.com/developerworks/opensource/
+ 97. http://www.ibm.com/developerworks/opensource/library/
+ 98. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#author1
+ 99. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#intro
+ 100. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#conclusion
+ 101. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 102. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/os-createcompilerllvm1-pdf.pdf
+ 103. http://www.adobe.com/products/acrobat/readstep2.html
+ 104. http://www.ibm.com/developerworks/cn/opensource/os-createcompilerllvm1/
+ 105. http://www.ibm.com/developerworks/ru/library/os-createcompilerllvm1/
+ 106. http://www.ibm.com/developerworks/jp/opensource/library/os-createcompilerllvm1/
+ 107. http://www.ibm.com/developerworks/views/opensource/libraryview.jsp?search_by=Create+a+working+compiler+with+the+LLVM+framework
+ 108. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 109. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 110. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 111. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 112. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 113. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-pcon
+ 114. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list1
+ 115. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list2
+ 116. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-pcon
+ 117. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 118. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 119. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list3
+ 120. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list3
+ 121. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 122. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list4
+ 123. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-pcon
+ 124. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 125. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 126. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list5
+ 127. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list6
+ 128. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list6
+ 129. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list7
+ 130. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list7
+ 131. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list8
+ 132. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list8
+ 133. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list9
+ 134. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list9
+ 135. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list10
+ 136. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list11
+ 137. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#list12
+ 138. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-pcon
+ 139. http://www.ibm.com/developerworks/views/opensource/libraryview.jsp?search_by=Create+a+working+compiler+with+the+LLVM+framework
+ 140. http://www.ibm.com/developerworks/library/os-createcompilerllvm2/index.html
+ 141. http://llvm.org/docs/tutorial/index.html
+ 142. http://www.aosabook.org/en/llvm.html
+ 143. http://llvm.org/releases/3.0/docs/CommandGuide/html/llc.html
+ 144. http://llvm.org/releases/3.0/docs/CommandGuide/html/lli.html
+ 145. http://llvm.org/docs/GCCFEBuildInstrs.html
+ 146. http://llvm.org/docs/LangRef.html
+ 147. http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/llvm.grm
+ 148. http://llvm.org/docs/GetElementPtr.html
+ 149. http://llvm.org/docs/ProgrammersManual.html
+ 150. http://llvm.org/cmds/llvm-config.html
+ 151. http://www.ibm.com/developerworks/opensource/
+ 152. http://www.ibm.com/developerworks/linux/index.html
+ 153. http://www.ibm.com/developerworks/views/linux/libraryview.jsp
+ 154. http://www.ibm.com/developerworks/web/
+ 155. http://www.ibm.com/developerworks/offers/techbriefings/events.html
+ 156. http://www.ibm.com/developerworks/offers/techbriefings/index.html
+ 157. http://www.ibm.com/developerworks/offers/lp/demos/index.html
+ 158. http://www.twitter.com/developerworks/
+ 159. http://search.twitter.com/search?q=%23linux+from%3Adeveloperworks+-RT+
+ 160. http://www.ibm.com/developerworks/downloads/index.html
+ 161. http://www.ibm.com/developerworks/downloads/soasandbox/index.html
+ 162. http://www.ibm.com/developerworks/blogs/
+ 163. http://www.ibm.com/developerworks/community
+ 164. http://www.ibm.com/developerworks/community
+ 165. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 166. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 167. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 168. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 169. http://www.ibm.com/developerworks/dwwi/jsp/WSHelp.jsp?lang=en_US
+ 170. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 171. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 172. https://www.ibm.com/developerworks/community/terms/
+ 173. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 174. https://www.ibm.com/developerworks/community/terms/
+ 175. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#ibm-pcon
+ 176. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#started
+ 177. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#hello
+ 178. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#llvm_ir
+ 179. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#generator
+ 180. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#conclusion
+ 181. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#resources
+ 182. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#author
+ 183. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/#icomments
+ 184. http://www.ibm.com/developerworks/opensource/
+ 185. http://www.ibm.com/developerworks/opensource/newto/
+ 186. http://www.ibm.com/developerworks/opensource/find/projects/
+ 187. http://www.ibm.com/developerworks/opensource/library/
+ 188. http://www.ibm.com/developerworks/forums/dw_osforums.jsp
+ 189. http://www.ibm.com/developerworks/opensource/find/events/
+ 190. https://www.ibm.com/developerworks/puresystems/try/?ca=dti-hivis-troy
+ 191. http://www.ibm.com/developerworks/demos/
+ 192. http://www.ibm.com/developerworks/aboutdw/dwa/?ca=dti-dwarp
+ 193. https://www.ibm.com/developerworks/cloud/index.html?ca=dti-cloudzone
+ 194. http://www.ibm.com/developerworks/downloads/?ca=dti-tilemoreoffers
+ 195. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 196. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 197. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 198. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 199. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 200. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 201. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 202. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 203. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 204. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 205. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 206. http://www.facebook.com/developerworks
+ 207. http://twitter.com/developerWorks
+ 208. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/
+ 209. http://www.ibm.com/developerworks/aboutdw/
+ 210. https://www.ibm.com/developerworks/feedback
+ 211. http://www.ibm.com/developerworks/aboutdw/contacts.html
+ 212. https://www.ibm.com/developerworks/ideas
+ 213. http://www.ibm.com/developerworks/feeds/
+ 214. https://www.ibm.com/developerworks/community/report/
+ 215. https://www.ibm.com/developerworks/community/terms/
+ 216. http://www.ibm.com/privacy/
+ 217. http://www.ibm.com/accessibility/
+ 218. http://www.ibm.com/developerworks/university/academicinitiative/
+ 219. http://www.ibm.com/developerworks/university/students/
+ 220. http://www.ibm.com/isv/
+ 221. http://www.ibm.com/developerworks/
+ 222. http://www.ibm.com/developerworks/cn/
+ 223. http://www.ibm.com/developerworks/jp/
+ 224. http://www.ibm.com/developerworks/ru/
+ 225. http://www.ibm.com/developerworks/br/
+ 226. http://www.ibm.com/developerworks/ssa/
+ 227. http://www.ibm.com/developerworks/vn/
diff --git a/old/toy/doc/os-createcompilerllvm2.txt b/old/toy/doc/os-createcompilerllvm2.txt
new file mode 100644
index 0000000..d04b962
--- /dev/null
+++ b/old/toy/doc/os-createcompilerllvm2.txt
@@ -0,0 +1,1341 @@
+
+ [1]Skip to main content
+ * [2]dW
+ * [3]Sign in (or register)
+ * [4]English
+ * [5][userid]
+ * [6]IBM
+
+ IBM ID: ____________________
+ Password: ____________________
+
+ [_] Keep me signed in.
+
+ By clicking Submit, you agree to the [7]developerWorks terms of use.
+ Submit
+ * [8]Need an IBM ID?
+ * [9]Forgot your IBM ID?
+
+ * [10]Forgot your password?
+ * [11]Change your password
+
+ The first time you sign into developerWorks, a profile is created for
+ you. Select information in your profile (name, country/region, and
+ company) is displayed to the public and will accompany any content you
+ post. You may update your IBM account at any time.
+
+ All information submitted is secure.
+ * [12]Close [x]
+
+ The first time you sign in to developerWorks, a profile is created for
+ you, so you need to choose a display name. Your display name
+ accompanies the content you post on developerworks.
+
+ Please choose a display name between 3-31 characters. Your display name
+ must be unique in the developerWorks community and should not be your
+ email address for privacy reasons.
+ Display name: _________________________
+
+ By clicking Submit, you agree to the [13]developerWorks terms of use.
+ Submit
+
+ All information submitted is secure.
+ * [14]Close [x]
+
+My developerWorks:
+
+ * [15]My home
+ * [16]My profile
+ * [17]My communities
+ * [18]Settings
+
+My notifications:
+
+ * [19]{[num_notify] new notifications}([num_notify] new notification)
+ * [20]{[num_invite] network requests}([num_invite] network request)
+
+ * [21]Sign out
+
+ * [22]Close [x]
+
+Select a language:
+
+ * [23]English
+ * [24]­
+ * [25]¥¬
+ * [26]Russkij
+
+ * [27]Português (Brasil)
+ * [28]Español
+ * [29]Vie>-.t
+
+ * [30]Close [x]
+
+ * [31]IBM home
+ * [32]Industries & solutions
+ * [33]Services
+ * [34]Products
+ * [35]Support & downloads
+
+ * [36]Product information
+ * [37]Redbooks
+ * [38]Software
+ * [39]Software services
+
+ * [40]Close [x]
+
+ * [41]developerWorks®
+
+ * [42]Technical topics
+ * [43]Evaluation software
+ * [44]Community
+ * [45]Events
+
+ Search developerWorks ____________________ Search
+
+[46]Technical topics
+
+ * [47]Agile transformation
+ * [48]AIX and UNIX
+ * [49]Big data
+ * [50]Business analytics
+ * [51]Business process management
+
+ * [52]Cloud computing
+ * [53]Commerce
+ * [54]IBM i
+ * [55]Industries
+ * [56]Information management
+
+ * [57]Java technology
+ * [58]Linux
+ * [59]Lotus (collaboration)
+ * [60]Mobile development
+ * [61]Open source
+
+ * [62]Rational
+ * [63]Security
+ * [64]Tivoli (service management)
+ * [65]Web development
+ * [66]WebSphere
+
+ * [67]Technical library
+ * [68]Products A to Z
+
+ * [69]Close [x]
+
+[70]Evaluation software
+
+ * [71]Business analytics
+ * [72]Information management
+ * [73]Lotus (collaboration)
+ * [74]Rational
+
+ * [75]Tivoli (service management)
+ * [76]WebSphere
+ * [77]More IBM products (Mobile, PureSystems, Security...)
+
+ * [78]Close [x]
+
+[79]Community
+
+ * [80]My home
+ * [81]Profiles
+ * [82]Communities
+
+ * [83]Blogs
+ * [84]Forums
+ * [85]Wikis
+
+ * [86]Activities
+ * [87]Podcasts
+ * [88]IBM Champion program
+
+ * [89]Close [x]
+
+[90]Events
+
+ * [91]Webcasts
+ * [92]Find events (webcasts, conferences...)
+
+ * [93]Close [x]
+
+ * [94]developerWorks
+ * [95]Technical topics
+ * [96]Open source
+ * [97]Technical library
+
+Create a working compiler with the LLVM framework, Part 2
+
+ Use clang to preprocess C/C++ code
+ [98]Arpan Sen, Author, Independent
+ Arpan Sen is a lead engineer working on the development of software in
+ the electronic design automation industry. He has worked on several
+ flavors of UNIX, including Solaris, SunOS, HP-UX, and IRIX, as well as
+ Linux and Microsoft Windows for several years. He takes a keen interest
+ in software performance-optimization techniques, graph theory, and
+ parallel computing. Arpan holds a post-graduate degree in software
+ systems.
+
+ Summary: The LLVM compiler infrastructure provides a powerful way to
+ optimize your applications regardless of the programming language you
+ use. Learn to instrument code in LLVM, using the clang API to
+ preprocess C/C++ code in this second article of a two-part series.
+
+ Date: 19 Jun 2012
+ Level: Intermediate
+ PDF: [99]A4 and Letter (300 KB | 16 pages)[100]Get Adobe® Reader®
+ Also available in: [101]Chinese [102]Russian [103]Japanese
+ [104]Portuguese
+ Activity: 47646 views
+ Comments:
+
+Other articles in this series
+
+ View more articles in the [105]Create a working compiler with the LLVM
+ framework series.
+
+ The [106]first article in this series explored LLVM intermediate
+ representation (IR). You hand-crafted a "Hello World" test program;
+ learned some of LLVM's nuances, like type casting; and finished it off
+ by creating the same program using LLVM application programming
+ interfaces (APIs). In the process, you also learned about LLVM tools
+ such as llc and lli and figured out how to use llvm-gcc to emit LLVM IR
+ for you. This second and concluding part of the series explores some of
+ the other cool things that you can do with LLVM. Specifically, it looks
+ at instrumenting code--that is, adding information to the final
+ executable that is generated. It also explores a bit of clang, a front
+ end for LLVM supporting C, C++, and Objective-C. You use the clang API
+ to preprocess and generate an abstract syntax tree (AST) for C/C++
+ code.
+
+ LLVM passes
+
+ LLVM is known for the optimization features it provides. Optimizations
+ are implemented as passes (for high-level details about LLVM passes,
+ see [107]Resources). The thing to note here is that LLVM provides you
+ with the ability to create utility passes with minimum code. For
+ example, if you don't want your function names to begin with "hello,"
+ you can have a utility pass to do just that.
+
+ Understanding the LLVM opt tool
+
+ From the man page for opt, the "opt command is the modular LLVM
+ optimizer and analyzer." Once you have the code for the custom pass
+ ready, you compile it into a shared library and load it using opt. If
+ your LLVM installation went well, opt should already be available in
+ your system. The opt command accepts both LLVM IR (the .ll extension)
+ and LLVM bit-code formats (the .bc extension) and can generate the
+ output as either LLVM IR or bit-code. Here's how you use opt to load
+ your custom shared library:
+tintin# opt -load=mycustom_pass.so -help -S
+
+ Also note that running opt -help from the command line generates a
+ laundry list of passes that LLVM performs. Using the load option with
+ help generates a help message that includes information about your
+ custom pass.
+
+ Creating a custom LLVM pass
+
+ You declare LLVM passes in the Pass.h file, which on my system is
+ installed under /usr/include/llvm. This file defines the interface for
+ an individual pass as part of the Pass class. Individual pass types,
+ each derived from Pass, are also declared in this file. Pass types
+ include:
+ * BasicBlockPass class. Used to implement local optimizations, with
+ optimizations typically operating on a basic block or instruction
+ at a time
+ * FunctionPass class. Used for global optimizations, one function at
+ a time
+ * ModulePass class. Used to perform just about any unstructured
+ interprocedural optimizations
+
+ Because you intend to create a pass that should object to any function
+ names beginning with "Hello," it's imperative that you create your own
+ pass by deriving from FunctionPass. Copy the code in [108]Listing 1
+ from Pass.h.
+ Listing 1. Overriding the runOnFunction class in FunctionPass
+
+Class FunctionPass : public Pass {
+ /// explicit FunctionPass(char &pid) : Pass(PT_Function, pid) {}
+ /// runOnFunction - Virtual method overridden by subclasses to do the
+ /// per-function processing of the pass.
+ ///
+ virtual bool runOnFunction(Function &F) = 0;
+ /// ...
+};
+
+ Likewise, the BasicBlockPass class declares a runOnBasicBlock, and the
+ ModulePass class declares a runOnModule pure virtual method. The child
+ class needs to provide a definition for the virtual method.
+
+ Coming back to the runOnFunction method in [109]Listing 1, you see that
+ the input is an object of type Function. Dig into the
+ /usr/include/llvm/Function.h file to easily see that the Function class
+ is what LLVM uses to encapsulate the functionality of a C/C++ function.
+ Function in turn is derived from the Value class defined in Value.h and
+ supports a getName method. [110]Listing 2 shows the code.
+ Listing 2. Creating a custom LLVM pass
+
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+class TestClass : public llvm::FunctionPass {
+public:
+virtual bool runOnFunction(llvm::Function &F)
+ {
+ if (F.getName().startswith("hello"))
+ {
+ std::cout << "Function name starts with hello\n";
+ }
+ return false;
+ }
+};
+
+ The code in [111]Listing 2 misses out on two important details:
+ * The FunctionPass constructor needs a char, which is used internally
+ by LLVM. LLVM uses the address of the char, so what you use to
+ initialize it should not matter.
+ * You need some way for the LLVM system to understand that the class
+ you created is a new pass. This is where the RegisterPass LLVM
+ template comes in. You declare the RegisterPass template in the
+ PassSupport.h header file; this file is included in Pass.h, so you
+ don't need additional headers.
+
+ [112]Listing 3 shows the complete code.
+ Listing 3. Registering the LLVM Function pass
+
+class TestClass : public llvm::FunctionPass
+{
+public:
+ TestClass() : llvm::FunctionPass(TestClass::ID) { }
+ virtual bool runOnFunction(llvm::Function &F) {
+ if (F.getName().startswith("hello")) {
+ std::cout << "Function name starts with hello\n";
+ }
+ return false;
+ }
+ static char ID; // could be a global too
+};
+char TestClass::ID = 'a';
+static llvm::RegisterPass<TestClass> global_("test_llvm", "test llvm", false, fa
+lse);
+
+ The template parameter in the RegisterPass template is the name of the
+ pass to be used on the command line with opt. That's it: All you need
+ to do now is create a shared library out of the code in [113]Listing 3,
+ and then run opt to load the library followed by the name of the
+ command you registered using RegisterPass--in this case, test_llvm--and
+ finally a bit-code file on which your custom pass will run along with
+ the other passes. The steps are outlined in [114]Listing 4.
+ Listing 4. Running the custom pass
+
+bash$ g++ -c pass.cpp -I/usr/local/include `llvm-config --cxxflags`
+bash$ g++ -shared -o pass.so pass.o -L/usr/local/lib `llvm-config --ldflags -lib
+s`
+bash$ opt -load=./pass.so -test_llvm < test.bc
+
+ Now look at the other side of the coin--the front end to the LLVM back
+ end: clang.
+ __________________________________________________________________
+
+ [115]Back to top
+
+ Introducing clang
+
+Notes before you begin
+
+ Clang is work in progress, and as is obvious with any project of this
+ scale, the documentation is typically behind the code base. As such,
+ it's best to check out the developer mailing list (see [116]Resources
+ for a link). You might want to have clang sources built and installed:
+ To do so, follow the instructions in the clang getting started guide
+ (see [117]Resources). Note that you need to issue the make install
+ command after the build is complete for installation to default system
+ folders. The rest of this article assumes that the clang headers and
+ libraries reside in system folders similar to /usr/local/include and
+ /usr/local/lib, respectively.
+
+ LLVM has its own front end--a tool (appropriately enough) called clang.
+ Clang is a powerful C/C++/Objective-C compiler, with compilation speeds
+ comparable to or better than GNU Compiler Collection (GCC) tools (see
+ [118]Resources for a link to more information). More importantly, clang
+ has a hackable code base, making for easy custom extensions. Much like
+ the way you used the LLVM back-end API for your custom plug-in in
+ [119]Part 1, in this article you use the API for the LLVM front end and
+ develop some small applications for preprocessing and parsing.
+
+ Common clang classes
+
+ You need to familiarize yourself with some of the most common clang
+ classes:
+ * CompilerInstance
+ * Preprocessor
+ * FileManager
+ * SourceManager
+ * DiagnosticsEngine
+ * LangOptions
+ * TargetInfo
+ * ASTConsumer
+ * Sema
+ * ParseAST is perhaps the most important clang method.
+
+ More on the ParseAST method shortly.
+
+ For all practical purposes, consider CompilerInstance the compiler
+ proper. It provides interfaces and manages access to the AST,
+ preprocesses the input sources, and maintains the target information.
+ Typical applications need to create a CompilerInstance object to do
+ anything useful. [120]Listing 5 provides a sneak peek into the
+ CompilerInstance.h header file.
+ Listing 5. The CompilerInstance class
+
+class CompilerInstance : public ModuleLoader {
+ /// The options used in this compiler instance.
+ llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
+ /// The diagnostics engine instance.
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ /// The target being compiled for.
+ llvm::IntrusiveRefCntPtr<TargetInfo> Target;
+ /// The file manager.
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ /// The source manager.
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ /// The preprocessor.
+ llvm::IntrusiveRefCntPtr<Preprocessor> PP;
+ /// The AST context.
+ llvm::IntrusiveRefCntPtr<ASTContext> Context;
+ /// The AST consumer.
+ OwningPtr<ASTConsumer> Consumer;
+ /// \brief The semantic analysis object.
+ OwningPtr<Sema> TheSema;
+ //... the list continues
+};
+ __________________________________________________________________
+
+ [121]Back to top
+
+ Preprocessing a C file
+
+ There are at least two ways to create a preprocessor object in clang:
+ * Directly instantiate a Preprocessor object
+ * Use the CompilerInstance class to create a Preprocessor object for
+ you
+
+ Let's begin with the latter approach.
+
+ Helper and utility classes needed for preprocessing
+
+ The Preprocessor alone won't be of much help: You need the FileManager
+ and SourceManager classes for reading files and tracking source
+ locations for diagnostics. The FileManager class implements support for
+ file system lookup, file system caching, and directory search. Look
+ into the FileEntry class, which defines the clang abstraction for a
+ source file. [122]Listing 6 provides an excerpt from the FileManager.h
+ header file.
+ Listing 6. The clang FileManager class
+
+class FileManager : public llvm::RefCountedBase<FileManager> {
+ FileSystemOptions FileSystemOpts;
+ /// \brief The virtual directories that we have allocated. For each
+ /// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent
+ /// directories (foo/ and foo/bar/) here.
+ SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries;
+ /// \brief The virtual files that we have allocated.
+ SmallVector<FileEntry*, 4> VirtualFileEntries;
+ /// NextFileUID - Each FileEntry we create is assigned a unique ID #.
+ unsigned NextFileUID;
+ // Statistics.
+ unsigned NumDirLookups, NumFileLookups;
+ unsigned NumDirCacheMisses, NumFileCacheMisses;
+ // ...
+ // Caching.
+ OwningPtr<FileSystemStatCache> StatCache;
+
+ The SourceManager class is typically queried for SourceLocation
+ objects. From the SourceManager.h header file, information about
+ SourceLocation objects is provided in [123]Listing 7.
+ Listing 7. Understanding SourceLocation
+
+/// There are three different types of locations in a file: a spelling
+/// location, an expansion location, and a presumed location.
+///
+/// Given an example of:
+/// #define min(x, y) x < y ? x : y
+///
+/// and then later on a use of min:
+/// #line 17
+/// return min(a, b);
+///
+/// The expansion location is the line in the source code where the macro
+/// was expanded (the return statement), the spelling location is the
+/// location in the source where the macro was originally defined,
+/// and the presumed location is where the line directive states that
+/// the line is 17, or any other line.
+
+ Clearly, SourceManager depends on FileManager behind the scenes;
+ indeed, the SourceManager class constructor accepts a FileManager class
+ as the input argument. Finally, you need to keep track of errors you
+ might encounter while processing the source and report the same. You do
+ so using the DiagnosticsEngine class. As with Preprocessor, you have
+ two options:
+ * Create all the necessary objects on your own
+ * Let the CompilerInstance do everything for you
+
+ Let's stick with the latter option. [124]Listing 8 shows the code for
+ the Preprocessor; everything else has already been explained.
+ Listing 8. Creating a preprocessor with the clang API
+
+using namespace clang;
+int main()
+{
+ CompilerInstance ci;
+ ci.createDiagnostics(0,NULL); // create DiagnosticsEngine
+ ci.createFileManager(); // create FileManager
+ ci.createSourceManager(ci.getFileManager()); // create SourceManager
+ ci.createPreprocessor(); // create Preprocessor
+ const FileEntry *pFile = ci.getFileManager().getFile("hello.c");
+ ci.getSourceManager().createMainFileID(pFile);
+ ci.getPreprocessor().EnterMainSourceFile();
+ ci.getDiagnosticClient().BeginSourceFile(ci.getLangOpts(), &ci.getPreprocess
+or());
+ Token tok;
+ do {
+ ci.getPreprocessor().Lex(tok);
+ if( ci.getDiagnostics().hasErrorOccurred())
+ break;
+ ci.getPreprocessor().DumpToken(tok);
+ std::cerr << std::endl;
+ } while ( tok.isNot(clang::tok::eof));
+ ci.getDiagnosticClient().EndSourceFile();
+}
+
+ [125]Listing 8 uses the CompilerInstance class to serially create the
+ DiagnosticsEngine (the ci.createDiagnostics method call) and
+ FileManager (ci.createFileManager and ci.CreateSourceManager) for you.
+ Once the file association is done using FileEntry, continue processing
+ each token in the source file until you reach end of file (EOF). The
+ preprocessor's DumpToken method dumps the token on screen.
+
+ To compile and run the code in [126]Listing 8, use the makefile
+ provided in [127]Listing 9, with appropriate adjustments for your clang
+ and LLVM installation folders. The idea is to use the llvm-config tool
+ to provide any necessary LLVM include paths and libraries: You should
+ never attempt to hand link those on a g++ command line.
+ Listing 9. Makefile for building preprocessor code
+
+CXX := g++
+RTTIFLAG := -fno-rtti
+CXXFLAGS := $(shell llvm-config --cxxflags) $(RTTIFLAG)
+LLVMLDFLAGS := $(shell llvm-config --ldflags --libs)
+DDD := $(shell echo $(LLVMLDFLAGS))
+SOURCES = main.cpp
+OBJECTS = $(SOURCES:.cpp=.o)
+EXES = $(OBJECTS:.o=)
+CLANGLIBS = \
+ -L /usr/local/lib \
+ -lclangFrontend \
+ -lclangParse \
+ -lclangSema \
+ -lclangAnalysis \
+ -lclangAST \
+ -lclangLex \
+ -lclangBasic \
+ -lclangDriver \
+ -lclangSerialization \
+ -lLLVMMC \
+ -lLLVMSupport \
+all: $(OBJECTS) $(EXES)
+%: %.o
+ $(CXX) -o $@ $< $(CLANGLIBS) $(LLVMLDFLAGS)
+
+ After compiling and running the above code, you should get the output
+ in [128]Listing 10.
+ Listing 10. Crash while running the coding in Listing 7
+
+Assertion failed: (Target && "Compiler instance has no target!"),
+ function getTarget, file
+ /Users/Arpan/llvm/tools/clang/lib/Frontend/../..
+ /include/clang/Frontend/CompilerInstance.h,
+ line 294.
+Abort trap: 6
+
+ What happened here is that you missed out on one last piece of the
+ CompilerInstance settings: the target platform for which this code
+ should be compiled. This is where the TargetInfo and TargetOptions
+ classes come in. According to the clang header TargetInfo.h, the
+ TargetInfo class stores the necessary information about the target
+ system for the code generation and has to be created before compilation
+ or preprocessing can ensue. As expected, TargetInfo seems to have
+ information about integer and float widths, alignments, and the like.
+ [129]Listing 11 provides an excerpt from the TargetInfo.h header file.
+ Listing 11. The clang TargetInfo class
+
+class TargetInfo : public llvm::RefCountedBase<TargetInfo> {
+ llvm::Triple Triple;
+protected:
+ bool BigEndian;
+ unsigned char PointerWidth, PointerAlign;
+ unsigned char IntWidth, IntAlign;
+ unsigned char HalfWidth, HalfAlign;
+ unsigned char FloatWidth, FloatAlign;
+ unsigned char DoubleWidth, DoubleAlign;
+ unsigned char LongDoubleWidth, LongDoubleAlign;
+ // ...
+
+ The TargetInfo class takes in two arguments for its initialization:
+ DiagnosticsEngine and TargetOptions. Of these, the latter must have the
+ Triple string set to the appropriate value for the current platform.
+ This is where LLVM comes in handy. [130]Listing 12 shows the addition
+ to [131]Listing 9 to make the preprocessor work.
+ Listing 12. Setting the target options for the compiler
+
+int main()
+{
+ CompilerInstance ci;
+ ci.createDiagnostics(0,NULL);
+ // create TargetOptions
+ TargetOptions to;
+ to.Triple = llvm::sys::getDefaultTargetTriple();
+ // create TargetInfo
+ TargetInfo *pti = TargetInfo::CreateTargetInfo(ci.getDiagnostics(), to);
+ ci.setTarget(pti);
+ // rest of the code same as in Listing 9...
+ ci.createFileManager();
+ // ...
+
+ That's it. Run this code and see what output you get for the simple
+ hello.c test:
+#include <stdio.h>
+int main() { printf("hello world!\n"); }
+
+ [132]Listing 13 shows the partial preprocessor output.
+ Listing 13. Preprocessor output (partial)
+
+typedef 'typedef'
+struct 'struct'
+identifier '__va_list_tag'
+l_brace '{'
+unsigned 'unsigned'
+identifier 'gp_offset'
+semi ';'
+unsigned 'unsigned'
+identifier 'fp_offset'
+semi ';'
+void 'void'
+star '*'
+identifier 'overflow_arg_area'
+semi ';'
+void 'void'
+star '*'
+identifier 'reg_save_area'
+semi ';'
+r_brace '}'
+identifier '__va_list_tag'
+semi ';'
+
+identifier '__va_list_tag'
+identifier '__builtin_va_list'
+l_square '['
+numeric_constant '1'
+r_square ']'
+semi ';'
+
+ Hand-crafting a Preprocessor object
+
+ One of the good things about clang libraries, you can achieve the same
+ result in multiple ways. In this section, you craft a Preprocessor
+ object but without making a direct request to CompilerInstance. From
+ the Preprocessor.h header file, [133]Listing 14 shows the constructor
+ for the Preprocessor.
+ Listing 14. Constructing a Preprocessor object
+
+Preprocessor(DiagnosticsEngine &diags, LangOptions &opts,
+ const TargetInfo *target,
+ SourceManager &SM, HeaderSearch &Headers,
+ ModuleLoader &TheModuleLoader,
+ IdentifierInfoLookup *IILookup = 0,
+ bool OwnsHeaderSearch = false,
+ bool DelayInitialization = false);
+
+ Looking at the constructor, it's clear that you need to create six
+ different objects before this beast can start up. You already know
+ DiagnosticsEngine, TargetInfo, and SourceManager. CompilerInstance is
+ derived from ModuleLoader. So you must create two new objects--one for
+ LangOptions and another for HeaderSearch. The LangOptions class lets
+ you compile a range of C/C++ dialects, including C99, C11, and C++0x.
+ Refer to the LangOptions.h and LangOptions.def headers for more
+ information. Finally, the HeaderSearch class stores an std::vector of
+ directories to search, amidst other things. [134]Listing 15 shows the
+ code for the Preprocessor.
+ Listing 15. Hand-crafted preprocessor
+
+using namespace clang;
+int main() {
+ DiagnosticOptions diagnosticOptions;
+ TextDiagnosticPrinter *printer =
+ new TextDiagnosticPrinter(llvm::outs(), diagnosticOptions);
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs;
+ DiagnosticsEngine diagnostics(diagIDs, printer);
+ LangOptions langOpts;
+ clang::TargetOptions to;
+ to.Triple = llvm::sys::getDefaultTargetTriple();
+ TargetInfo *pti = TargetInfo::CreateTargetInfo(diagnostics, to);
+ FileSystemOptions fsopts;
+ FileManager fileManager(fsopts);
+ SourceManager sourceManager(diagnostics, fileManager);
+ HeaderSearch headerSearch(fileManager, diagnostics, langOpts, pti);
+ CompilerInstance ci;
+ Preprocessor preprocessor(diagnostics, langOpts, pti,
+ sourceManager, headerSearch, ci);
+ const FileEntry *pFile = fileManager.getFile("test.c");
+ sourceManager.createMainFileID(pFile);
+ preprocessor.EnterMainSourceFile();
+ printer->BeginSourceFile(langOpts, &preprocessor);
+ // ... similar to Listing 8 here on
+}
+
+ Note a few things about the code in [135]Listing 15:
+ * You have not initialized HeaderSearch to point to any specific
+ directories. You should do so.
+ * The clang API requires that TextDiagnosticPrinter be allocated on
+ the heap. Allocating on the stack causes a crash.
+ * You have not been able to get rid of CompilerInstance. Because you
+ are using CompilerInstance anyway, why bother to hand-craft it at
+ all other than to be more comfortable with the clang API?
+
+ Language option: C++
+
+ You have worked with C test code so far: How about a bit of C++, then?
+ To the code in [136]Listing 15, add langOpts.CPlusPlus = 1;, and try it
+ with the test code in [137]Listing 16.
+ Listing 16. C++ test code for the preprocessor
+
+template <typename T, int n>
+struct s {
+ T array[n];
+};
+int main() {
+ s<int, 20> var;
+}
+
+ [138]Listing 17 shows the partial output from your program.
+ Listing 17. Partial preprocessor output from the code in Listing 16
+
+identifier 'template'
+less '<'
+identifier 'typename'
+identifier 'T'
+comma ','
+int 'int'
+identifier 'n'
+greater '>'
+struct 'struct'
+identifier 's'
+l_brace '{'
+identifier 'T'
+identifier 'array'
+l_square '['
+identifier 'n'
+r_square ']'
+semi ';'
+r_brace '}'
+semi ';'
+int 'int'
+identifier 'main'
+l_paren '('
+r_paren ')'
+ __________________________________________________________________
+
+ [139]Back to top
+
+ Creating a parse tree
+
+ The ParseAST method defined in clang/Parse/ParseAST.h is one of the
+ more important methods that clang provides. Here's one of the
+ declaration of the routine, copied from ParseAST.h:
+void ParseAST(Preprocessor &pp, ASTConsumer *C,
+ ASTContext &Ctx, bool PrintStats = false,
+ TranslationUnitKind TUKind = TU_Complete,
+ CodeCompleteConsumer *CompletionConsumer = 0);
+
+ ASTConsumer provides you with an abstract interface from which to
+ derive. This is the right thing to do, because different clients are
+ likely to dump or process the AST in different ways. Your client code
+ will be derived from ASTConsumer. The ASTContext class stores--among
+ other things--information about type declarations. Here's the easiest
+ thing to try: Print a list of global variables in your code using the
+ clang ASTConsumer API. Many tech firms have strict rules about global
+ variable usage in C++ code, and this could be the starting point of
+ creating your custom lint tool. The code for your custom consumer is
+ provided in [140]Listing 18.
+ Listing 18. A custom AST consumer class
+
+class CustomASTConsumer : public ASTConsumer {
+public:
+ CustomASTConsumer () : ASTConsumer() { }
+ virtual ~ CustomASTConsumer () { }
+ virtual bool HandleTopLevelDecl(DeclGroupRef decls)
+ {
+ clang::DeclGroupRef::iterator it;
+ for( it = decls.begin(); it != decls.end(); it++)
+ {
+ clang::VarDecl *vd = llvm::dyn_cast<clang::VarDecl>(*it);
+ if(vd)
+ std::cout << vd->getDeclName().getAsString() << std::endl;;
+ }
+ return true;
+ }
+};
+
+ You are overriding the HandleTopLevelDecl method (originally provided
+ in ASTConsumer) with your own version. Clang is passing the list of
+ globals to you; you iterate over the list and print the variable names.
+ Excerpted from ASTConsumer.h, [141]Listing 19 shows several other
+ methods that client consumer code could override.
+ Listing 19. Other methods you could override in client code
+
+/// HandleInterestingDecl - Handle the specified interesting declaration. This
+/// is called by the AST reader when deserializing things that might interest
+/// the consumer. The default implementation forwards to HandleTopLevelDecl.
+virtual void HandleInterestingDecl(DeclGroupRef D);
+
+/// HandleTranslationUnit - This method is called when the ASTs for entire
+/// translation unit have been parsed.
+virtual void HandleTranslationUnit(ASTContext &Ctx) {}
+
+/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
+/// (e.g. struct, union, enum, class) is completed. This allows the client to
+/// hack on the type, which can occur at any point in the file (because these
+/// can be defined in declspecs).
+virtual void HandleTagDeclDefinition(TagDecl *D) {}
+
+/// Note that at this point it does not have a body, its body is
+ /// instantiated at the end of the translation unit and passed to
+ /// HandleTopLevelDecl.
+ virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {}
+
+ Finally, [142]Listing 20 shows the actual client code using the custom
+ AST consumer class that you developed.
+ Listing 20. Client code using a custom AST consumer
+
+int main() {
+ CompilerInstance ci;
+ ci.createDiagnostics(0,NULL);
+ TargetOptions to;
+ to.Triple = llvm::sys::getDefaultTargetTriple();
+ TargetInfo *tin = TargetInfo::CreateTargetInfo(ci.getDiagnostics(), to);
+ ci.setTarget(tin);
+ ci.createFileManager();
+ ci.createSourceManager(ci.getFileManager());
+ ci.createPreprocessor();
+ ci.createASTContext();
+ CustomASTConsumer *astConsumer = new CustomASTConsumer ();
+ ci.setASTConsumer(astConsumer);
+ const FileEntry *file = ci.getFileManager().getFile("hello.c");
+ ci.getSourceManager().createMainFileID(file);
+ ci.getDiagnosticClient().BeginSourceFile(
+ ci.getLangOpts(), &ci.getPreprocessor());
+ clang::ParseAST(ci.getPreprocessor(), astConsumer, ci.getASTContext());
+ ci.getDiagnosticClient().EndSourceFile();
+ return 0;
+}
+ __________________________________________________________________
+
+ [143]Back to top
+
+ Conclusion
+
+Other articles in this series
+
+ View more articles in the [144]Create a working compiler with the LLVM
+ framework series.
+
+ This two-part series covered a lot of ground: It explored LLVM IR,
+ offered ways to generate IR through hand-crafting and LLVM APIs, showed
+ how to create a custom plug-in for the LLVM back end, and explained the
+ LLVM front end and its rich set of headers. You also learned how to use
+ this front end for preprocessing and AST consumption. Creating a
+ compiler and extending it, particularly for complex languages like C++,
+ had seemed like rocket science earlier in the history of computing, but
+ with LLVM, life has been simplified. Documentation is where LLVM and
+ clang still need work, but until that's sorted out, I recommend a fresh
+ cup of brew and VIM/doxygen to browse the headers. Have fun!
+
+ Resources
+
+ Learn
+ * Learn the basics of the LLVM in [145]Create a working compiler with
+ the LLVM framework, Part 1: Build a custom compiler with LLVM and
+ its intermediate representation (Arpan Sen, developerWorks, June
+ 2012). Optimize your applications regardless of the programming
+ language you use with the powerful the LLVM compiler
+ infrastructure. Building a custom compiler just got easier!
+ * Learn more about [146]LLVM passes.
+ * Get on the [147]clang developer mailing list.
+ * Read [148]Getting Started: Building and Running Clang for detailed
+ information on building and installing clang.
+ * Take the [149]official LLVM Tutorial for a great introduction to
+ LLVM.
+ * Dig into the [150]LLVM Programmer's Manual, an indispensable
+ resource for the LLVM API.
+ * The [151]Open Source developerWorks zone provides a wealth of
+ information on open source tools and using open source
+ technologies.
+ * In the [152]developerWorks Linux zone, find hundreds of [153]how-to
+ articles and tutorials, as well as downloads, discussion forums,
+ and a wealth of other resources for Linux developers and
+ administrators.
+ * [154]developerWorks Web development specializes in articles
+ covering various web-based solutions.
+ * Stay current with [155]developerWorks technical events and webcasts
+ focused on a variety of IBM products and IT industry topics.
+ * Attend a [156]free developerWorks Live! briefing to get up-to-speed
+ quickly on IBM products and tools, as well as IT industry trends.
+ * Watch [157]developerWorks on-demand demos ranging from product
+ installation and setup demos for beginners, to advanced
+ functionality for experienced developers.
+ * Follow [158]developerWorks on Twitter.
+
+ Get products and technologies
+ * Visit the [159]LLVM project site and download the [160]latest
+ version.
+ * Find details about [161]clang from the LLVM site.
+ * [162]Evaluate IBM products in the way that suits you best: Download
+ a product trial, try a product online, use a product in a cloud
+ environment, or spend a few hours in the [163]SOA Sandbox learning
+ how to implement Service Oriented Architecture efficiently.
+
+ Discuss
+ * Check out [164]developerWorks blogs and get involved in the
+ [165]developerWorks community.
+ * Get involved in the [166]developerWorks community. Connect with
+ other developerWorks users while exploring the developer-driven
+ blogs, forums, groups, and wikis.
+
+ About the author
+
+ Arpan Sen is a lead engineer working on the development of software in
+ the electronic design automation industry. He has worked on several
+ flavors of UNIX, including Solaris, SunOS, HP-UX, and IRIX, as well as
+ Linux and Microsoft Windows for several years. He takes a keen interest
+ in software performance-optimization techniques, graph theory, and
+ parallel computing. Arpan holds a post-graduate degree in software
+ systems.
+
+ [167]Close [x]
+ Report abuse help
+
+Report abuse
+
+ Thank you. This entry has been flagged for moderator attention.
+ __________________________________________________________________
+
+ [BUTTON Input] (not implemented)_____
+
+ [168]Close [x]
+ Report abuse help
+
+Report abuse
+
+ Report abuse submission failed. Please try again later.
+ __________________________________________________________________
+
+ [BUTTON Input] (not implemented)_____
+
+ [169]Close [x]
+
+developerWorks: Sign in
+
+ IBM ID: _________________________
+ [170]Need an IBM ID?
+ [171]Forgot your IBM ID?
+
+ Password: _________________________
+ [172]Forgot your password?
+ [173]Change your password
+
+ [_] Keep me signed in.
+
+ By clicking Submit, you agree to the [174]developerWorks terms of use.
+
+ Submit [BUTTON Input] (not implemented)______
+ __________________________________________________________________
+
+ The first time you sign into developerWorks, a profile is created for
+ you. Select information in your profile (name, country/region, and
+ company) is displayed to the public and will accompany any content you
+ post. You may update your IBM account at any time.
+
+ All information submitted is secure.
+
+ [175]Close [x]
+
+Choose your display name
+
+ The first time you sign in to developerWorks, a profile is created for
+ you, so you need to choose a display name. Your display name
+ accompanies the content you post on developerWorks.
+
+ Please choose a display name between 3-31 characters. Your display name
+ must be unique in the developerWorks community and should not be your
+ email address for privacy reasons.
+
+ Display name: _________________________(Must be between 3 - 31
+ characters.)
+
+ By clicking Submit, you agree to the [176]developerWorks terms of use.
+
+ Submit [BUTTON Input] (not implemented)______
+ __________________________________________________________________
+
+ All information submitted is secure.
+
+ Rate this article
+
+ Comments
+
+ [177]Back to top
+ static.content.url=http://www.ibm.com/developerworks/js/artrating/
+ SITE_ID=1
+ Zone=Open source, Linux
+ ArticleID=821110
+ ArticleTitle=Create a working compiler with the LLVM framework, Part 2
+ publish-date=06192012
+
+Table of contents
+
+ * [178]LLVM passes
+ * [179]Introducing clang
+ * [180]Preprocessing a C file
+ * [181]Creating a parse tree
+ * [182]Conclusion
+ * [183]Resources
+ * [184]About the author
+ * [185]Comments
+
+Next steps from IBM
+
+ Try the XL C/C++ compilers, downloadable for free.
+ __________________________________________________________________
+
+ * [186]Try: XL C/C++ for AIX
+ * [187]Community: Go to Rational C/C++ cafe to join the conversation.
+ * [188]Buy: XL C/C++ for AIX
+
+Dig deeper into Open source on developerWorks
+
+ * [189]Overview
+ * [190]New to Open source
+ * [191]Projects
+ * [192]Technical library (articles, tutorials, and more)
+ * [193]Forums
+ * [194]Events
+
+Try IBM PureSystems. No charge.
+
+ IBM PureSystems on a kaleideoscope background
+
+ Experience today!
+ __________________________________________________________________
+
+ [195]Get started with the cloud-based trial and pattern development
+ kit.
+
+Special offers
+
+ [196]On demand demos: An easy way to watch and learn
+
+ [197]Get recognized! W Author Program
+
+ [198]Cloud Computing resources for IT professionals
+ __________________________________________________________________
+
+ [199]Trial software offers
+ * [200]Print this page
+
+ * [201]Share this page
+ * [202]Follow developerWorks
+
+Share this page:
+
+ * [203]Facebook
+ * [204]LinkedIn
+ * [205]Twitter
+
+ * [206]Delicious
+ * [207]Digg
+ * [208]StumbleUpon
+
+ * [209]Email this page
+
+ * [210]Close [x]
+
+Follow developerWorks:
+
+ * [211]Facebook
+ * [212]Twitter
+
+ * [213]Close [x]
+
+ * [214]About
+ * [215]Help
+ * [216]Contact us
+ * [217]Submit content
+
+ * [218]Feeds
+
+ * [219]Report abuse
+ * [220]Terms of use
+ * [221]IBM privacy
+ * [222]IBM accessibility
+
+ * [223]Faculty
+ * [224]Students
+ * [225]Business Partners
+
+ IBM®
+
+Select a language:
+
+ * [226]English
+ * [227]­
+ * [228]¥¬
+ * [229]Russkij
+ * [230]Português (Brasil)
+ * [231]Español
+ * [232]Vie>-.t
+
+References
+
+ 1. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-content
+ 2. http://www.ibm.com/developerworks/
+ 3. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 4. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#SELECTLANG
+ 5. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 6. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 7. https://www.ibm.com/developerworks/community/terms/
+ 8. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 9. https://www.ibm.com/developerworks/dwwi/jsp/WSHelp.jsp?lang=en_US
+ 10. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 11. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 12. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 13. https://www.ibm.com/developerworks/community/terms/
+ 14. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 15. https://www.ibm.com/developerworks/community/homepage/web/updates/?lang=en
+ 16. https://www.ibm.com/developerworks/community/profiles/html/myProfileView.do?lang=en
+ 17. https://www.ibm.com/developerworks/community/groups/service/html/mycommunities?lang=en
+ 18. https://www.ibm.com/developerworks/community/news
+ 19. https://www.ibm.com/developerworks/community/homepage?lang=en
+ 20. https://www.ibm.com/developerworks/community/profiles/html/wc.do?action=in&requireAuth=true&widgetId=friends&lang=[lang]
+ 21. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 22. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 23. http://www.ibm.com/developerworks/
+ 24. http://www.ibm.com/developerworks/cn/
+ 25. http://www.ibm.com/developerworks/jp/
+ 26. http://www.ibm.com/developerworks/ru/
+ 27. http://www.ibm.com/developerworks/br/
+ 28. http://www.ibm.com/developerworks/ssa/
+ 29. http://www.ibm.com/developerworks/vn/
+ 30. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 31. http://www.ibm.com/
+ 32. http://www.ibm.com/solutions/
+ 33. http://www.ibm.com/technologyservices/
+ 34. http://www.ibm.com/products/
+ 35. http://www.ibm.com/support/
+ 36. http://www.ibm.com/support/publications/us/library/index.shtml
+ 37. http://www.ibm.com/redbooks/
+ 38. http://www.ibm.com/software/
+ 39. http://www.ibm.com/software/sw-services/
+ 40. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 41. http://www.ibm.com/developerworks/
+ 42. http://www.ibm.com/developerworks/topics/
+ 43. http://www.ibm.com/developerworks/downloads/
+ 44. http://www.ibm.com/developerworks/community/index.html
+ 45. http://www.ibm.com/developerworks/events/
+ 46. http://www.ibm.com/developerworks/topics/
+ 47. http://www.ibm.com/developerworks/agile/
+ 48. http://www.ibm.com/developerworks/aix/
+ 49. http://www.ibm.com/developerworks/bigdata/
+ 50. http://www.ibm.com/developerworks/analytics/
+ 51. http://www.ibm.com/developerworks/bpm/
+ 52. http://www.ibm.com/developerworks/cloud/
+ 53. http://www.ibm.com/developerworks/commerce/
+ 54. http://www.ibm.com/developerworks/ibmi/
+ 55. http://www.ibm.com/developerworks/industry/
+ 56. http://www.ibm.com/developerworks/data/
+ 57. http://www.ibm.com/developerworks/java/
+ 58. http://www.ibm.com/developerworks/linux/
+ 59. http://www.ibm.com/developerworks/lotus/
+ 60. http://www.ibm.com/developerworks/mobile/
+ 61. http://www.ibm.com/developerworks/opensource/
+ 62. http://www.ibm.com/developerworks/rational/
+ 63. http://www.ibm.com/developerworks/security/
+ 64. http://www.ibm.com/developerworks/servicemanagement/
+ 65. http://www.ibm.com/developerworks/web/
+ 66. http://www.ibm.com/developerworks/websphere/
+ 67. http://www.ibm.com/developerworks/library/
+ 68. http://www.ibm.com/developerworks/products/
+ 69. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 70. http://www.ibm.com/developerworks/downloads/
+ 71. http://www.ibm.com/developerworks/downloads/#ba
+ 72. http://www.ibm.com/developerworks/downloads/#data
+ 73. http://www.ibm.com/developerworks/downloads/#lotus
+ 74. http://www.ibm.com/developerworks/downloads/#rational
+ 75. http://www.ibm.com/developerworks/downloads/#tivoli
+ 76. http://www.ibm.com/developerworks/downloads/#websphere
+ 77. http://www.ibm.com/developerworks/downloads/#more
+ 78. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 79. https://www.ibm.com/developerworks/community/index.html
+ 80. https://www.ibm.com/developerworks/community/homepage/?lang=en
+ 81. https://www.ibm.com/developerworks/community/profiles/?lang=en
+ 82. https://www.ibm.com/developerworks/community/groups/?lang=en
+ 83. https://www.ibm.com/developerworks/community/blogs/?lang=en
+ 84. https://www.ibm.com/developerworks/community/forums/?lang=en
+ 85. https://www.ibm.com/developerworks/community/wikis/?lang=en
+ 86. https://www.ibm.com/developerworks/community/activities/?lang=en
+ 87. https://www.ibm.com/developerworks/community/podcasts/?lang=en
+ 88. https://www.ibm.com/developerworks/champion/
+ 89. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 90. http://www.ibm.com/developerworks/events/
+ 91. http://www.ibm.com/developerworks/find/webcasts/
+ 92. http://www.ibm.com/developerworks/find/events/
+ 93. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 94. http://www.ibm.com/developerworks/
+ 95. http://www.ibm.com/developerworks/topics/
+ 96. http://www.ibm.com/developerworks/opensource/
+ 97. http://www.ibm.com/developerworks/opensource/library/
+ 98. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#author1
+ 99. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/os-createcompilerllvm2-pdf.pdf
+ 100. http://www.adobe.com/products/acrobat/readstep2.html
+ 101. http://www.ibm.com/developerworks/cn/opensource/os-createcompilerllvm2/
+ 102. http://www.ibm.com/developerworks/ru/library/os-createcompilerllvm2/
+ 103. http://www.ibm.com/developerworks/jp/opensource/library/os-createcompilerllvm2/
+ 104. http://www.ibm.com/developerworks/br/library/os-createcompilerllvm2/
+ 105. http://www.ibm.com/developerworks/views/opensource/libraryview.jsp?search_by=Create+a+working+compiler+with+the+LLVM+framework
+ 106. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/index.html
+ 107. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#resources
+ 108. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list1
+ 109. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list1
+ 110. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list2
+ 111. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list2
+ 112. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list3
+ 113. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list3
+ 114. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list4
+ 115. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-pcon
+ 116. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#resources
+ 117. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#resources
+ 118. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#resources
+ 119. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/index.html
+ 120. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list5
+ 121. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-pcon
+ 122. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list6
+ 123. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list7
+ 124. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list8
+ 125. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list8
+ 126. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list8
+ 127. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list9
+ 128. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list10
+ 129. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list11
+ 130. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list12
+ 131. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list9
+ 132. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list13
+ 133. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list14
+ 134. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list15
+ 135. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list15
+ 136. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list15
+ 137. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list16
+ 138. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list17
+ 139. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-pcon
+ 140. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list18
+ 141. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list19
+ 142. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#list20
+ 143. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-pcon
+ 144. http://www.ibm.com/developerworks/views/opensource/libraryview.jsp?search_by=Create+a+working+compiler+with+the+LLVM+framework
+ 145. http://www.ibm.com/developerworks/library/os-createcompilerllvm1/index.html
+ 146. http://llvm.org/docs/Passes.html
+ 147. http://lists.cs.uiuc.edu/pipermail/cfe-dev
+ 148. http://clang.llvm.org/get_started.html
+ 149. http://llvm.org/docs/tutorial/index.html
+ 150. http://llvm.org/docs/ProgrammersManual.html
+ 151. http://www.ibm.com/developerworks/opensource/
+ 152. http://www.ibm.com/developerworks/linux/index.html
+ 153. http://www.ibm.com/developerworks/views/linux/libraryview.jsp
+ 154. http://www.ibm.com/developerworks/web/
+ 155. http://www.ibm.com/developerworks/offers/techbriefings/events.html
+ 156. http://www.ibm.com/developerworks/offers/techbriefings/index.html
+ 157. http://www.ibm.com/developerworks/offers/lp/demos/index.html
+ 158. http://www.twitter.com/developerworks/
+ 159. http://www.llvm.org/
+ 160. http://llvm.org/releases
+ 161. http://clang.llvm.org/
+ 162. http://www.ibm.com/developerworks/downloads/index.html
+ 163. http://www.ibm.com/developerworks/downloads/soasandbox/index.html
+ 164. http://www.ibm.com/developerworks/blogs/
+ 165. http://www.ibm.com/developerworks/community
+ 166. http://www.ibm.com/developerworks/community
+ 167. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 168. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 169. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 170. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 171. https://www.ibm.com/developerworks/dwwi/jsp/WSHelp.jsp?lang=en_US
+ 172. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 173. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 174. https://www.ibm.com/developerworks/community/terms/
+ 175. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 176. https://www.ibm.com/developerworks/community/terms/
+ 177. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#ibm-pcon
+ 178. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#passes
+ 179. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#clang
+ 180. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#preprocess_c
+ 181. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#tree
+ 182. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#N104AA
+ 183. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#resources
+ 184. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#author
+ 185. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/#icomments
+ 186. http://www.ibm.com/developerworks/downloads/r/xlcplusaix/
+ 187. https://www.ibm.com/developerworks/rational/community/cafe/ccpp.html
+ 188. http://www.ibm.com/software/dre/h2b/buildh2bpage.wss?synkey=Z842241J60251I44
+ 189. http://www.ibm.com/developerworks/opensource/
+ 190. http://www.ibm.com/developerworks/opensource/newto/
+ 191. http://www.ibm.com/developerworks/opensource/find/projects/
+ 192. http://www.ibm.com/developerworks/opensource/library/
+ 193. http://www.ibm.com/developerworks/forums/dw_osforums.jsp
+ 194. http://www.ibm.com/developerworks/opensource/find/events/
+ 195. https://www.ibm.com/developerworks/puresystems/try/?ca=dti-hivis-troy
+ 196. http://www.ibm.com/developerworks/demos/
+ 197. http://www.ibm.com/developerworks/aboutdw/dwa/?ca=dti-dwarp
+ 198. https://www.ibm.com/developerworks/cloud/index.html?ca=dti-cloudzone
+ 199. http://www.ibm.com/developerworks/downloads/?ca=dti-tilemoreoffers
+ 200. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 201. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 202. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 203. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 204. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 205. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 206. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 207. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 208. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 209. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 210. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 211. http://www.facebook.com/developerworks
+ 212. http://twitter.com/developerWorks
+ 213. https://www.ibm.com/developerworks/library/os-createcompilerllvm2/
+ 214. http://www.ibm.com/developerworks/aboutdw/
+ 215. https://www.ibm.com/developerworks/feedback
+ 216. http://www.ibm.com/developerworks/aboutdw/contacts.html
+ 217. https://www.ibm.com/developerworks/ideas
+ 218. http://www.ibm.com/developerworks/feeds/
+ 219. https://www.ibm.com/developerworks/community/report/
+ 220. https://www.ibm.com/developerworks/community/terms/
+ 221. http://www.ibm.com/privacy/
+ 222. http://www.ibm.com/accessibility/
+ 223. http://www.ibm.com/developerworks/university/academicinitiative/
+ 224. http://www.ibm.com/developerworks/university/students/
+ 225. http://www.ibm.com/isv/
+ 226. http://www.ibm.com/developerworks/
+ 227. http://www.ibm.com/developerworks/cn/
+ 228. http://www.ibm.com/developerworks/jp/
+ 229. http://www.ibm.com/developerworks/ru/
+ 230. http://www.ibm.com/developerworks/br/
+ 231. http://www.ibm.com/developerworks/ssa/
+ 232. http://www.ibm.com/developerworks/vn/
diff --git a/old/toy/grammar.l b/old/toy/grammar.l
new file mode 100644
index 0000000..110afb7
--- /dev/null
+++ b/old/toy/grammar.l
@@ -0,0 +1,34 @@
+%{
+ #include <iostream>
+ #include "node.hpp"
+ #include "grammar.hpp"
+
+ #define YYLEX grammarlex
+
+ #define SAVE_TOKEN grammarlval.string = new std::string( yytext, yyleng )
+ #define DEBUG( what ) std::cerr << "DEBUG: " << what << " '" << yytext << "'" << std::endl
+ #define TOKEN( t ) ( grammarlval.token = t )
+%}
+
+%%
+
+[ \t\n] ;
+[a-zA-Z_][a-zA-Z0-9_]* DEBUG( "TIDENTIFIER" ); SAVE_TOKEN; return TIDENTIFIER;
+[0-9]+ DEBUG( "TINTEGER" ); SAVE_TOKEN; return TINTEGER;
+"(" DEBUG( "TLPAREN" ); return TOKEN( TLPAREN );
+")" DEBUG( "TRPAREN" ); return TOKEN( TRPAREN );
+"{" DEBUG( "TLBRACE" ); return TOKEN( TLBRACE );
+"}" DEBUG( "TRBRACE" ); return TOKEN( TRBRACE );
+"=" DEBUG( "TEQUAL" ); return TOKEN( TEQUAL );
+"*" DEBUG( "TMUL" ); return TOKEN( TMUL );
+"+" DEBUG( "TPLUS" ); return TOKEN( TPLUS );
+"," DEBUG( "TCOMMA" ); return TOKEN( TCOMMA );
+"//".* // ignore comments;
+. std::cerr << "ERROR: Unknown token '" << yytext << "'" << std::endl; yyterminate( );
+
+%%
+
+int grammarwrap( void )
+{
+ return 1;
+}
diff --git a/old/toy/grammar.y b/old/toy/grammar.y
new file mode 100644
index 0000000..a449952
--- /dev/null
+++ b/old/toy/grammar.y
@@ -0,0 +1,103 @@
+%{
+ #include <iostream>
+ #include <cstdlib>
+ #include "node.hpp"
+
+ // AST
+ NBlock *programBlock = 0;
+
+ extern int grammarlex( );
+ extern int grammarget_lineno( void );
+
+ void grammarerror( const char *s )
+ {
+ std::cerr << "ERROR in line " << grammarget_lineno( ) << ": " << s << std::endl;
+ exit( 1 );
+ }
+%}
+
+%union {
+ Node *node;
+ NBlock *block;
+ NStatement *stmt;
+ NExpression *expr;
+ NIdentifier *ident;
+ NVariableDeclaration *var_decl;
+ std::vector<NVariableDeclaration*> *vars;
+ std::string *string;
+ ExpressionList *exprs;
+ int token;
+}
+
+%token <string> TIDENTIFIER TINTEGER
+%token <token> TLPAREN TRPAREN TLBRACE TRBRACE
+%token <token> TCOMMA
+%token <token> TEQUAL TMUL TPLUS
+
+%type <block> program stmts block
+%type <ident> ident
+%type <expr> numeric expr
+%type <stmt> stmt func_decl var_decl
+%type <vars> func_decl_args
+%type <exprs> call_args
+%type <token> operator
+
+%left TEQUAL
+%left TPLUS
+%left TMUL
+
+%start program
+
+%%
+
+program : stmts { programBlock = $1; }
+ ;
+
+stmts : stmt { $$ = new NBlock( ); $$->m_statements.push_back( $1 ); }
+ | stmts stmt { $1->m_statements.push_back( $2 ); }
+ ;
+
+stmt : var_decl { }
+ | func_decl { }
+ | expr { $$ = new NExpressionStatement( *$1 ); }
+ ;
+
+func_decl : ident ident TLPAREN func_decl_args TRPAREN block
+ { $$ = new NFunctionDeclaration( *$1, *$2, *$4, *$6 ); delete $4; }
+ ;
+
+func_decl_args : /* procedure */ { $$ = new VariableList( ); }
+ | var_decl { $$ = new VariableList( ); $$->push_back( $<var_decl>1 ); }
+ | func_decl_args TCOMMA var_decl { $1->push_back( $<var_decl>3 ); }
+ ;
+
+var_decl : ident ident { $$ = new NVariableDeclaration( *$1, *$2 ); }
+ | ident ident TEQUAL expr { $$ = new NVariableDeclaration( *$1, *$2, $4 ); }
+ ;
+
+expr : numeric { }
+ | ident { $<ident>$ = $1; }
+ | expr operator expr { $$ = new NBinaryOperator( *$1, $2, *$3 ); }
+ | ident TLPAREN call_args TRPAREN { $$ = new NFunctionCall( *$1, *$3 ); delete $3; }
+ ;
+
+call_args : /* no params */ { $$ = new ExpressionList( ); }
+ | expr { $$ = new ExpressionList( ); $$->push_back( $1 ); }
+ | call_args TCOMMA expr { $1->push_back( $3 ); }
+ ;
+
+operator : TMUL | TPLUS
+ ;
+
+numeric : TINTEGER { $$ = new NInteger( atoi( $1->c_str( ) ) ); delete $1; }
+ ;
+
+block : TLBRACE /* empty block */ TRBRACE { $$ = new NBlock( ); }
+ | TLBRACE stmts TRBRACE { $$ = $2; }
+ ;
+
+ident : TIDENTIFIER { $$ = new NIdentifier( *$1 ); delete $1; }
+ ;
+
+%%
+
diff --git a/old/toy/main.cpp b/old/toy/main.cpp
new file mode 100644
index 0000000..68b4957
--- /dev/null
+++ b/old/toy/main.cpp
@@ -0,0 +1,35 @@
+#include <iostream>
+#include <fstream>
+#include "node.hpp"
+#include "codegen.hpp"
+
+extern int grammarparse( void );
+extern NBlock* programBlock;
+
+int main( )
+{
+ std::cout << "-- lexical analysis" << std::endl;
+ grammarparse( );
+
+ std::cout << "-- syntactic analysis and ADT construction" << std::endl
+ << *programBlock << std::endl;
+
+ CodeGenContext context;
+
+ std::cout << "-- generating LLVM code" << std::endl;
+ context.generateCode( *programBlock );
+
+ std::cout << "-- generated LLVM code" << std::endl;
+ context.printGeneratedCode( );
+
+ std::cout << "-- running the LLVM code" << std::endl;
+ llvm::InitializeNativeTarget( );
+ context.runCode( );
+
+ std::ofstream o( "test.llvm" );
+ std::string code = context.getGeneratedCode( );
+ o << code;
+ o.flush( );
+
+ return 0;
+}
diff --git a/old/toy/node.cpp b/old/toy/node.cpp
new file mode 100644
index 0000000..ed24f4c
--- /dev/null
+++ b/old/toy/node.cpp
@@ -0,0 +1,118 @@
+#include "node.hpp"
+#include "grammar.hpp"
+
+std::ostream& operator<<( std::ostream& o, const Node& n )
+{
+ n.printTo( o );
+ return o;
+}
+
+void Node::printTo( std::ostream& o ) const
+{
+ o << "<abstract node>";
+}
+
+void NBlock::printTo(std::ostream& o ) const
+{
+ o << "NBlock[" << std::endl;
+ StatementList::const_iterator eit = m_statements.end( );
+ for( StatementList::const_iterator it = m_statements.begin( );
+ it != eit; it++ ) {
+ o << "\t";
+ (*it)->printTo( o );
+ o << std::endl;
+ }
+ o << "]" << std::endl;
+}
+
+void NInteger::printTo( std::ostream& o ) const
+{
+ o << "NInteger[" << m_value << "]";
+}
+
+void NStatement::printTo(std::ostream& o ) const
+{
+ o << "NStatement";
+}
+
+void NExpressionStatement::printTo( std::ostream& o ) const
+{
+ o << "NStatement[" << m_expression << "]";
+}
+
+void NIdentifier::printTo( std::ostream& o ) const
+{
+ o << "NIdentifier['" << m_name << "']";
+}
+
+void NAssignment::printTo( std::ostream& o ) const
+{
+ o << "NAssignment[" << m_lhs << " = " << m_rhs << "]";
+}
+
+void NVariableDeclaration::printTo( std::ostream& o ) const
+{
+ o << "NVariableDeclaration[";
+ m_type.printTo( o );
+ o << " ";
+ m_name.printTo( o );
+ if( m_assigned_expr != 0 ) {
+ o << "=";
+ m_assigned_expr->printTo( o );
+ }
+ o << "]";
+}
+
+void NFunctionDeclaration::printTo( std::ostream& o ) const
+{
+ o << "NFunctionDeclaration[returns: ";
+ m_type.printTo( o );
+ o << ", name: ";
+ m_name.printTo( o );
+ if( m_arguments.size( ) > 0 ) {
+ o << ", params: ";
+ VariableList::const_iterator eit = m_arguments.end( );
+ for( VariableList::const_iterator it = m_arguments.begin( );
+ it != eit; ) {
+ (*it)->printTo( o );
+ it++;
+ if( it != eit ) {
+ o << ",";
+ }
+ }
+ }
+ o << ":" << std::endl;
+ m_block.printTo( o );
+ o << "]";
+}
+
+void NFunctionCall::printTo( std::ostream& o ) const
+{
+ o << "NFunctionCall, ";
+ o << "name: " << m_name << " (";
+ ExpressionList::const_iterator eit = m_arguments.end( );
+ for( ExpressionList::const_iterator it = m_arguments.begin( );
+ it != eit; ) {
+ (*it)->printTo( o );
+ it++;
+ if( it != eit ) {
+ o << ",";
+ }
+ }
+ o << ")";
+}
+
+void NBinaryOperator::printTo( std::ostream& o ) const
+{
+ o << "NExpression[";
+ m_lhs.printTo( o );
+ o << " ";
+ switch( m_op ) {
+ case TPLUS: o << "+"; break;
+ case TMUL: o << "*"; break;
+ default: o << "<unknown operator>"; break;
+ }
+ o << " ";
+ m_rhs.printTo( o );
+ o << "]";
+}
diff --git a/old/toy/node.hpp b/old/toy/node.hpp
new file mode 100644
index 0000000..ab0bdd7
--- /dev/null
+++ b/old/toy/node.hpp
@@ -0,0 +1,168 @@
+#ifndef __NODE_HPP_
+#define __NODE_HPP_
+
+#include <string>
+#include <iostream>
+#include <vector>
+
+#include <llvm/IR/Value.h>
+
+class NStatement;
+class NExpression;
+class NVariableDeclaration;
+class CodeGenContext;
+
+typedef std::vector<NStatement *> StatementList;
+typedef std::vector<NExpression *> ExpressionList;
+typedef std::vector<NVariableDeclaration*> VariableList;
+
+// abstract type, never constructuted, defines the public interface to the AST
+class Node {
+ public:
+ virtual ~Node( ) { }
+
+ friend std::ostream& operator<<( std::ostream& o, const Node& n );
+
+ virtual void printTo( std::ostream& o ) const;
+
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+// an expression
+class NExpression : public Node
+{
+};
+
+// a block of statements
+class NBlock : public NExpression
+{
+ public:
+ StatementList m_statements;
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NStatement : public Node
+{
+ public:
+ virtual void printTo( std::ostream& o ) const;
+};
+
+class NExpressionStatement : public NStatement
+{
+ public:
+ NExpression& m_expression;
+
+ NExpressionStatement( NExpression& _expression ) : m_expression( _expression ) { }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+// simple integer constant
+class NInteger : public NExpression
+{
+ public:
+ int m_value;
+
+ NInteger( int _value ) : m_value( _value ) { }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NIdentifier : public Node
+{
+ public:
+ std::string m_name;
+ NIdentifier( const std::string& _name ) : m_name( _name ) { }
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NAssignment : public NExpression
+{
+ public:
+ NIdentifier& m_lhs;
+ NExpression& m_rhs;
+
+ NAssignment( NIdentifier& _lhs, NExpression& _rhs ) : m_lhs( _lhs ), m_rhs( _rhs ) { }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NVariableDeclaration : public NStatement
+{
+ public:
+ const NIdentifier& m_type;
+ NIdentifier& m_name;
+ NExpression *m_assigned_expr;
+
+ NVariableDeclaration( const NIdentifier& _type, NIdentifier& _name )
+ : m_type( _type ), m_name( _name ), m_assigned_expr( 0 )
+ {
+ }
+
+ NVariableDeclaration( const NIdentifier& _type, NIdentifier& _name, NExpression *_assigned_expr )
+ : m_type( _type ), m_name( _name ), m_assigned_expr( _assigned_expr )
+ {
+ }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NFunctionDeclaration : public NStatement
+{
+ public:
+ const NIdentifier& m_type;
+ const NIdentifier& m_name;
+ VariableList m_arguments;
+ NBlock& m_block;
+
+ NFunctionDeclaration( const NIdentifier& _type, const NIdentifier& _name,
+ const VariableList& _arguments, NBlock& _block )
+ : m_type( _type ), m_name( _name ), m_arguments( _arguments ), m_block( _block )
+ {
+ }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NFunctionCall : public NExpression
+{
+ public:
+ const NIdentifier& m_name;
+ ExpressionList m_arguments;
+
+ NFunctionCall( const NIdentifier& _name, ExpressionList& _arguments )
+ : m_name( _name ), m_arguments( _arguments )
+ {
+ }
+
+ NFunctionCall( const NIdentifier& _name ) : m_name( _name ) { }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+class NBinaryOperator : public NExpression {
+ public:
+ NExpression& m_lhs;
+ NExpression& m_rhs;
+ int m_op;
+
+ NBinaryOperator( NExpression& _lhs, int _op, NExpression& _rhs )
+ : m_lhs( _lhs ), m_rhs( _rhs ), m_op( _op )
+ {
+ }
+
+ virtual void printTo( std::ostream& o ) const;
+ virtual llvm::Value* codeGen( CodeGenContext& context );
+};
+
+
+#endif //__NODE_HPP_
diff --git a/old/toy/test.c b/old/toy/test.c
new file mode 100644
index 0000000..9bbb8a0
--- /dev/null
+++ b/old/toy/test.c
@@ -0,0 +1,23 @@
+void foo()
+{
+}
+
+int do_math(int a)
+{
+ int y = 7
+ int z = 8
+ int zz = y
+// zz = x
+ int x = a * 5 + 3
+}
+
+int multiply(int x, int y)
+{
+ int res = x * y
+}
+
+foo()
+do_math(20)
+int blu = 20
+int res = do_math(blu)
+//echo(res)