compiler/libec2: Initial go at a handwritten Recursive Descent parser
authorJerome St-Louis <jerome@ecere.com>
Sun, 7 Jul 2013 00:36:42 +0000 (20:36 -0400)
committerJerome St-Louis <jerome@ecere.com>
Mon, 21 Nov 2016 14:19:00 +0000 (09:19 -0500)
12 files changed:
compiler/libec2/ec2.epj [new file with mode: 0644]
compiler/libec2/parser.ec [new file with mode: 0644]
compiler/libec2/rdParser.epj [new file with mode: 0644]
compiler/libec2/src/astNode.ec [new file with mode: 0644]
compiler/libec2/src/classes.ec [new file with mode: 0644]
compiler/libec2/src/declarators.ec [new file with mode: 0644]
compiler/libec2/src/expressions.ec [new file with mode: 0644]
compiler/libec2/src/externals.ec [new file with mode: 0644]
compiler/libec2/src/lexing.ec [new file with mode: 0644]
compiler/libec2/src/specifiers.ec [new file with mode: 0644]
compiler/libec2/src/statements.ec [new file with mode: 0644]
compiler/libec2/test.ec [new file with mode: 0644]

diff --git a/compiler/libec2/ec2.epj b/compiler/libec2/ec2.epj
new file mode 100644 (file)
index 0000000..f3896db
--- /dev/null
@@ -0,0 +1,52 @@
+{
+   "Version" : 0.2,
+   "ModuleName" : "ec2",
+   "Options" : {
+      "Warnings" : "All",
+      "TargetType" : "SharedLibrary",
+      "TargetFileName" : "ec2",
+      "Libraries" : [
+         "ecere"
+      ]
+   },
+   "Configurations" : [
+      {
+         "Name" : "Debug",
+         "Options" : {
+            "Debug" : true,
+            "Optimization" : "None",
+            "PreprocessorDefinitions" : [
+               "_DEBUG"
+            ],
+            "FastMath" : false
+         }
+      },
+      {
+         "Name" : "Release",
+         "Options" : {
+            "Debug" : false,
+            "Optimization" : "Speed",
+            "FastMath" : true
+         }
+      }
+   ],
+   "Files" : [
+      {
+         "Folder" : "src",
+         "Files" : [
+            "lexing.ec",
+            "expressions.ec",
+            "statements.ec",
+            "declarators.ec",
+            "specifiers.ec",
+            "classes.ec",
+            "externals.ec",
+            "astNode.ec"
+         ]
+      }
+   ],
+   "ResourcesPath" : "",
+   "Resources" : [
+
+   ]
+}
diff --git a/compiler/libec2/parser.ec b/compiler/libec2/parser.ec
new file mode 100644 (file)
index 0000000..eaf56dc
--- /dev/null
@@ -0,0 +1,44 @@
+public import "ecere"
+public import "ec2"
+
+class Form1 : Window
+{
+   caption = "Form1";
+   background = activeBorder;
+   borderStyle = sizable;
+   hasMaximize = true;
+   hasMinimize = true;
+   hasClose = true;
+   clientSize = { 632, 438 };
+
+   Button button1
+   {
+      this, caption = "Parse", isDefault = true, position = { 184, 144 };
+
+      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
+      {
+         File f = FileOpen("test.ec", read);
+         if(f)
+         {
+            initParser(f);
+            {
+               AST ast = AST::parse();
+               if(ast)
+                  ast.print();
+            }
+            /*
+            {
+               ASTExpression exp = ASTExpression::parse();
+               exp.print();
+               PrintLn("");
+               PrintLn(exp.Compute());
+            }
+            */
+            delete f;
+         }
+         return true;
+      }
+   };
+};
+
+Form1 form1 {};
diff --git a/compiler/libec2/rdParser.epj b/compiler/libec2/rdParser.epj
new file mode 100644 (file)
index 0000000..5e9000e
--- /dev/null
@@ -0,0 +1,41 @@
+{
+   "Version" : 0.2,
+   "ModuleName" : "rdParser",
+   "Options" : {
+      "Warnings" : "All",
+      "TargetType" : "Executable",
+      "TargetFileName" : "rdParser",
+      "Libraries" : [
+         "ecere"
+      ],
+      "Console" : true
+   },
+   "Configurations" : [
+      {
+         "Name" : "Debug",
+         "Options" : {
+            "Debug" : true,
+            "Optimization" : "None",
+            "PreprocessorDefinitions" : [
+               "_DEBUG"
+            ],
+            "FastMath" : false
+         }
+      },
+      {
+         "Name" : "Release",
+         "Options" : {
+            "Debug" : false,
+            "Optimization" : "Speed",
+            "FastMath" : true
+         }
+      }
+   ],
+   "Files" : [
+      "parser.ec"
+   ],
+   "ResourcesPath" : "",
+   "Resources" : [
+
+   ]
+}
diff --git a/compiler/libec2/src/astNode.ec b/compiler/libec2/src/astNode.ec
new file mode 100644 (file)
index 0000000..efaf934
--- /dev/null
@@ -0,0 +1,74 @@
+import "lexing"
+
+public class ASTNode : Container
+{
+public:
+   Location loc;
+
+   virtual void print();
+}
+
+public class ASTList : ASTNode
+{
+   List<ASTNode> list { };
+
+   IteratorPointer GetFirst()                             { return list ? list.GetFirst() : 0; }
+   IteratorPointer GetLast()                              { return list ? list.GetLast() : 0; }
+   IteratorPointer GetPrev(IteratorPointer pointer)       { return list ? list.GetPrev(pointer) : 0; }
+   IteratorPointer GetNext(IteratorPointer pointer)       { return list ? list.GetNext(pointer) : 0; }
+   bool SetData(IteratorPointer pointer, D data)          { return list ? list.SetData(pointer, (ASTNode)data) : 0; }
+   D GetData(IteratorPointer pointer)                     { return list ? list.GetData(pointer) : (D)0; }
+   IteratorPointer GetAtPosition(I pos, bool create)      { return list ? list.GetAtPosition((int)pos, create) : 0; }
+   IteratorPointer Insert(Link after, T value)            { return list ? list.Insert(after, (void *)value) : 0; }
+   IteratorPointer Add(T value)                           { return list ? list.Add((void *)value) : 0; }
+   void Remove(IteratorPointer it)                        { if(list) list.Remove(it); }
+   void Move(IteratorPointer it, IteratorPointer after)   { if(list) list.Move(it, after); }
+   void RemoveAll()                                       { if(list) list.RemoveAll(); }
+   void Copy(Container<T> source)                         { if(list) list.Copy(source); }
+   IteratorPointer Find(D value)                          { return list ? list.Find((void *)value) : 0; }
+   void FreeIterator(IteratorPointer it)                  { if(list) list.FreeIterator(it); }
+   int GetCount()                                         { return list ? list.GetCount() : 0; }
+   void Free()                                            { if(list) list.Free(); }
+   void Delete(IteratorPointer i)                         { if(list) list.Delete(i); }
+
+public:
+   virtual void printSep()
+   {
+      Print(", ");
+   }
+
+   void print()
+   {
+      Iterator<ASTNode> it { list };
+      while(it.Next())
+      {
+         it.data.print();
+         if(list.GetNext(it.pointer))
+            printSep();
+      }
+   }
+
+   Container ::parse(subclass(Container) c, ASTNode parser(), char sep)
+   {
+      Container<ASTNode> list = null;
+      while(true)
+      {
+         ASTNode e = parser();
+         if(e)
+         {
+            if(!list) list = eInstance_New(c);
+            list.Add(e);
+         }
+         if(peekToken().type == sep)
+            readToken();
+         else
+            break;
+      }
+      return list;
+   }
+
+   ~ASTList()
+   {
+      list.Free();
+   }
+}
diff --git a/compiler/libec2/src/classes.ec b/compiler/libec2/src/classes.ec
new file mode 100644 (file)
index 0000000..19ccc89
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+public class ClassFunction : struct
+{
+public:
+   ClassFunction prev, next;
+   Location loc;
+   OldList * specifiers;
+   ASTDeclarator declarator;
+   OldList * declarations;
+   Statement body;
+   Class _class;
+   OldList attached;    // For IDE
+   AccessMode declMode;
+   
+   // COMPILING DATA
+   Type type;
+   Symbol propSet;
+
+   bool isVirtual;
+   bool isConstructor, isDestructor;
+   bool dontMangle;
+   int id, idCode;
+};
+
+public class MembersInit : struct
+{
+public:
+   MembersInit prev, next;
+   Location loc;
+   MembersInitType type;
+   union
+   {
+      OldList * dataMembers;
+      ClassFunction function;
+   };
+   //bool coloned;
+};
+
+public class MemberInit : struct
+{
+public:
+   MemberInit prev, next;
+   Location loc;
+   Location realLoc;
+   OldList * identifiers;
+   // Expression exp;
+   Initializer initializer;
+
+   // COMPILE DATA
+   bool used;
+   bool variable;
+   bool takeOutExp;
+};
+
+public class ClassDefinition : struct
+{
+public:
+   ClassDefinition prev, next;
+   Location loc;
+   Specifier _class;
+   // Specifier base;
+   OldList * baseSpecs;
+   OldList * definitions;
+   Symbol symbol;
+   Location blockStart;
+   Location nameLoc;
+   int endid;
+   AccessMode declMode;
+   bool deleteWatchable;
+};
+*/
+
+/*
+public class PropertyDef : struct
+{
+public:
+   PropertyDef prev, next;
+   Location loc;
+   OldList * specifiers;
+   ASTDeclarator declarator;
+   Identifier id;
+   Statement getStmt;
+   Statement setStmt;
+   Statement issetStmt;
+   Symbol symbol;
+   bool conversion;
+   bool isWatchable;
+   Expression category;
+};
+
+public class ClassDef : struct
+{
+public:
+   ClassDef prev, next;
+   Location loc;
+   ClassDefType type;
+   union
+   {
+      Declaration decl;
+      ClassFunction function;
+      OldList * defProperties;
+      PropertyDef propertyDef;
+      ASTPropertyWatch propertyWatch;
+      char * designer;
+      Identifier defaultProperty;
+      struct
+      {
+         Identifier id;
+         Initializer initializer;
+      };
+   };
+   AccessMode memberAccess;
+
+   // IDE
+   void * object;
+};
+*/
diff --git a/compiler/libec2/src/declarators.ec b/compiler/libec2/src/declarators.ec
new file mode 100644 (file)
index 0000000..a2ffad4
--- /dev/null
@@ -0,0 +1,272 @@
+import "expressions"
+
+public class ASTPointer : ASTNode
+{
+   SpecsList qualifiers;
+   ASTPointer pointer;
+
+   void print()
+   {
+      Print("*");
+      if(qualifiers) qualifiers.print();
+      if(pointer) pointer.print();
+   }   
+
+   ASTPointer ::parse()
+   {
+      ASTPointer ptr { };
+      readToken();
+      while(peekToken().type == '*')
+      {
+         readToken();
+         ptr = { pointer = ptr };
+      }
+      return ptr;
+   }
+}
+
+public class ASTDeclarator : ASTNode
+{
+public:
+   DeclaratorType type;
+   // Symbol symbol;
+
+   ASTDeclarator ::parse()
+   {
+      ASTDeclarator decl = null;
+
+      if(peekToken().type == '*')
+         decl = DeclPointer::parse();
+      else
+      {
+         if(peekToken().type == IDENTIFIER)
+            decl = DeclIdentifier::parse();
+         else if(nextToken.type == '(')
+            decl = DeclBrackets::parse();
+         if(decl)
+         {
+            while(true)
+            {
+               if(peekToken().type == '[')
+                  decl = DeclArray::parse(decl);
+               else if(nextToken.type == '(')
+                  decl = DeclFunction::parse(decl);
+               else
+                  break;
+            }
+         }
+      }
+      return decl;
+   }
+}
+
+public class DeclFunction : ASTDeclarator
+{
+public:
+   ASTDeclarator declarator;
+   TypeNameList parameters;
+
+   void print()
+   {
+      if(declarator) declarator.print();
+      Print("(");
+      if(parameters) parameters.print();
+      Print(")");
+   }
+
+   DeclFunction ::parse(ASTDeclarator d)
+   {
+      DeclFunction decl { declarator = d };
+      readToken();
+      if(peekToken().type != ')') decl.parameters = TypeNameList::parse();
+      if(peekToken().type == ')') readToken();
+      return decl;
+   }
+}
+
+public class DeclIdentifier : ASTDeclarator
+{
+   ASTIdentifier identifier;
+
+   void print()
+   {
+      if(identifier) identifier.print();
+   }
+
+   DeclIdentifier ::parse()
+   {
+      return { identifier = ASTIdentifier::parse() };
+   }
+}
+
+public class DeclBrackets : ASTDeclarator
+{
+   ASTDeclarator declarator;
+
+   void print()
+   {
+      Print("(");
+      if(declarator) declarator.print();      
+      Print(")");
+   }
+
+   DeclBrackets ::parse()
+   {
+      DeclBrackets decl = null;
+      ASTDeclarator d;
+      readToken();
+      d = ASTDeclarator::parse();
+      if(d)
+         decl = { declarator = d };
+      if(peekToken().type == ')')
+         readToken();
+      return decl;
+   }
+}
+
+public class DeclArray : ASTDeclarator
+{
+   ASTDeclarator declarator;
+   ASTExpression exp;
+   // ASTSpecifier enumClass;
+
+   void print()
+   {
+      if(declarator) declarator.print();      
+      Print("[");
+      if(exp) exp.print();      
+      Print("]");
+   }
+
+   DeclArray ::parse(ASTDeclarator d)
+   {
+      DeclArray decl { declarator = d };
+      readToken();
+      if(peekToken().type != ']') decl.exp = ExpConditional::parse();
+      if(peekToken().type == ']') readToken();
+      return decl;
+   }
+}
+
+public class DeclPointer : ASTDeclarator
+{
+   ASTDeclarator declarator;
+   ASTPointer pointer;
+
+   void print()
+   {
+      if(pointer) pointer.print();
+      if(declarator) declarator.print();
+   }
+
+   DeclPointer ::parse()
+   {
+      return { pointer = ASTPointer::parse(), declarator = ASTDeclarator::parse() };
+   }
+}
+
+/*
+   union
+   {
+      struct
+      {
+         Expression exp;
+         Expression posExp;
+         Attrib attrib;
+      } structDecl;
+      struct
+      {
+         ExtDecl extended;
+      } extended;
+   };
+*/
+
+public class ASTInitializer : ASTNode
+{
+   // bool isConstant;
+   ASTInitializer ::parse()
+   {
+      if(peekToken().type == '{')
+      {
+         InitList init;
+         readToken();
+         init = InitList::parse();
+         if(peekToken().type == '}') readToken();
+         return init;
+      }
+      else
+         return InitExp { exp = ASTExpression::parse() };
+   }
+};
+
+public class InitExp : ASTInitializer
+{
+   ASTExpression exp;
+
+   void print()
+   {
+      if(exp)
+         exp.print();
+   }
+};
+
+public class InitList : ASTInitializer
+{
+   ASTList<ASTInitializer> list;
+
+   void print()
+   {
+      if(list)
+      {
+         Print("{ ");
+         list.print();
+         Print(" }");
+      }
+   }
+
+   InitList ::parse()
+   {
+      ASTList<ASTInitializer> list = (ASTList<ASTInitializer>)ASTList::parse(class(ASTList<ASTInitializer>), ASTInitializer::parse, ',');
+      return list ? { list = (void *)list } : null;
+   }
+};
+
+public class ASTInitDeclarator : ASTNode
+{
+   ASTDeclarator declarator;
+   ASTInitializer initializer;
+
+   void print()
+   {
+      if(declarator) declarator.print();
+      if(initializer)
+      {
+         Print(" = ");
+         initializer.print();
+      }
+   }
+
+   ASTInitDeclarator ::parse()
+   {
+      ASTDeclarator decl = ASTDeclarator::parse();
+      if(decl)
+      {
+         ASTInitializer init = null;
+         if(peekToken().type == '=')
+         {
+            readToken();
+            init = ASTInitializer::parse();
+         }
+         return { declarator = decl, initializer = init };
+      }
+      return null;
+   }
+};
+
+public class InitDeclList : ASTList<ASTInitDeclarator>
+{
+   InitDeclList ::parse()
+   {
+      return (InitDeclList)ASTList::parse(class(InitDeclList), ASTInitDeclarator::parse, ',');
+   }
+}
diff --git a/compiler/libec2/src/expressions.ec b/compiler/libec2/src/expressions.ec
new file mode 100644 (file)
index 0000000..b82ea47
--- /dev/null
@@ -0,0 +1,605 @@
+import "lexing"
+import "astNode"
+import "specifiers"
+import "declarators"
+
+static TokenType opPrec[][4] =
+{
+   { '*', '/', '%' },
+   { '+', '-' },
+   { LEFT_OP, RIGHT_OP },
+   { '<', '>', LE_OP, GE_OP },
+   { EQ_OP, NE_OP },
+   { '&' },
+   { '^' },
+   { '|' },
+   { AND_OP },
+   { OR_OP }
+};
+
+static define numPrec = sizeof(opPrec) / sizeof(opPrec[0]);
+
+static bool isPrecedence(TokenType this, int l)
+{
+   // TO OPTIMIZE: return opPrec[this] == l
+   if(this)
+   {
+      int o;
+      for(o = 0; o < sizeof(opPrec[0]) / sizeof(opPrec[0][0]); o++)
+      {
+         TokenType op = opPrec[l][o];
+         if(this == op)
+            return true;
+         else if(!op)
+            break;
+      }
+   }
+   return false;
+}
+
+public class ASTIdentifier : ASTNode
+{
+public:
+   // Symbol classSym;
+   // Specifier _class;
+   String string;
+   // Identifier badID;
+
+   void print()
+   {
+      Print(string);
+   }
+
+   ASTIdentifier ::parse()
+   {
+      readToken();
+      return { string = CopyString(token.text) };
+   }
+};
+
+public class ASTTypeName : ASTNode
+{
+public:
+   SpecsList qualifiers;
+   ASTDeclarator declarator;
+   ClassObjectType classObjectType;
+   ASTExpression bitCount;
+
+   ASTTypeName ::parse()
+   {
+      SpecsList specs = SpecsList::parse();
+      ASTDeclarator decl = ASTDeclarator::parse();
+      return { qualifiers = specs, declarator = decl };
+   }
+
+   void print()
+   {
+      if(qualifiers) qualifiers.print();
+      if(declarator) { if(qualifiers) Print(" "); declarator.print(); }
+   }
+};
+
+public class TypeNameList : ASTList<ASTTypeName>
+{
+   TypeNameList ::parse()
+   {
+      return (TypeNameList)ASTList::parse(class(TypeNameList), ASTTypeName::parse, ',');
+   }
+}
+
+// Expressions
+public class ASTExpression : ASTNode
+{
+public:
+   ExpressionType type;
+
+   virtual float Compute();
+
+   bool debugValue;
+
+   DataValue val;
+
+   uint64 address;
+   bool hasAddress;
+
+   // *** COMPILING DATA ***
+   Type expType;
+   Type destType;
+
+   ExpUsage usage;
+   int tempCount;
+   bool byReference;
+   bool isConstant;
+   bool addedThis;
+   bool needCast;
+   bool thisPtr;
+
+   ASTExpression ::parse()
+   {
+      return ExpAssignment::parse();
+   }
+/*
+   void Clear()
+   {
+      debugValue = false;
+      val = { 0 };
+      address = 0;
+      hasAddress = false;
+
+      expType = null;
+      destType = null;
+
+      usage = 0;
+      tempCount = 0;
+      byReference = false;
+      isConstant = false;
+      addedThis = false;
+      needCast = false;
+      thisPtr = false;
+   }
+*/
+}
+
+public class ListExp : ASTList<ASTExpression>
+{
+   ListExp ::parse()
+   {
+      return (ListExp)ASTList::parse(class(ListExp), ASTExpression::parse, ',');
+   }
+}
+
+/*
+public class ExpCompound : ASTExpression
+{
+   ASTStatement compound;
+}
+*/
+
+static ASTExpression parseSimplePrimaryExpression()
+{
+/*
+simple_primary_expression:
+     instantiation_unnamed      { $$ = MkExpInstance($1); $$.loc = @$; }
+   | EXTENSION '(' compound_statement ')'    { $$ = MkExpExtensionCompound($3); $$.loc = @$; }
+   | EXTENSION '(' expression ')'    { $$ = MkExpExtensionExpression($3); $$.loc = @$; }
+   | EXTENSION '(' type_name ')' initializer     { $$ = MkExpExtensionInitializer($3, $5); $$.loc = @$; }
+   | EXTENSION '(' type_name ')' '(' type_name ')' initializer     { $$ = MkExpExtensionInitializer($3, MkInitializerAssignment(MkExpExtensionInitializer($6, $8))); $$.loc = @$; }
+   | i18n_string
+   | '(' ')' { Expression exp = MkExpDummy(); exp.loc.start = @1.end; exp.loc.end = @2.start; $$ = MkExpBrackets(MkListOne(exp)); $$.loc = @$; yyerror(); }
+   | NEWOP new_specifiers abstract_declarator_noarray '[' constant_expression ']' { $$ = MkExpNew(MkTypeName($2,$3), $5); $$.loc = @$; }
+   | NEWOP new_specifiers abstract_declarator_noarray '[' constant_expression_error ']' { $$ = MkExpNew(MkTypeName($2,$3), $5); $$.loc = @$; }
+   | NEWOP new_specifiers '[' constant_expression ']' { $$ = MkExpNew(MkTypeName($2,null), $4); $$.loc = @$; }
+   | NEWOP new_specifiers '[' constant_expression_error ']' { $$ = MkExpNew(MkTypeName($2,null), $4); $$.loc = @$; }
+   | NEW0OP new_specifiers abstract_declarator_noarray '[' constant_expression ']' { $$ = MkExpNew0(MkTypeName($2,$3), $5); $$.loc = @$; }
+   | NEW0OP new_specifiers abstract_declarator_noarray '[' constant_expression_error ']' { $$ = MkExpNew0(MkTypeName($2,$3), $5); $$.loc = @$; }
+   | NEW0OP new_specifiers '[' constant_expression ']' { $$ = MkExpNew0(MkTypeName($2,null), $4); $$.loc = @$; }
+   | NEW0OP new_specifiers '[' constant_expression_error ']' { $$ = MkExpNew0(MkTypeName($2,null), $4); $$.loc = @$; }
+   | RENEW constant_expression renew_specifiers abstract_declarator_noarray '[' constant_expression ']' { $$ = MkExpRenew($2, MkTypeName($3,$4), $6); $$.loc = @$; }
+   | RENEW constant_expression renew_specifiers abstract_declarator_noarray '[' constant_expression_error ']' { $$ = MkExpRenew($2, MkTypeName($3,$4), $6); $$.loc = @$; }
+   | RENEW constant_expression renew_specifiers '[' constant_expression ']' { $$ = MkExpRenew($2, MkTypeName($3,null), $5); $$.loc = @$; }
+   | RENEW constant_expression renew_specifiers '[' constant_expression_error ']' { $$ = MkExpRenew($2, MkTypeName($3,null), $5); $$.loc = @$; }
+   | RENEW0 constant_expression renew_specifiers abstract_declarator_noarray '[' constant_expression ']' { $$ = MkExpRenew0($2, MkTypeName($3,$4), $6); $$.loc = @$; }
+   | RENEW0 constant_expression renew_specifiers abstract_declarator_noarray '[' constant_expression_error ']' { $$ = MkExpRenew0($2, MkTypeName($3,$4), $6); $$.loc = @$; }
+   | RENEW0 constant_expression renew_specifiers '[' constant_expression ']' { $$ = MkExpRenew0($2, MkTypeName($3,null), $5); $$.loc = @$; }
+   | RENEW0 constant_expression renew_specifiers '[' constant_expression_error ']' { $$ = MkExpRenew0($2, MkTypeName($3,null), $5); $$.loc = @$; }
+   | CLASS '(' declaration_specifiers ')' { $$ = MkExpClass($3, null); $$.loc = @$; }
+   | CLASS '(' declaration_specifiers abstract_declarator ')' { $$ = MkExpClass($3, $4); $$.loc = @$; }
+   | CLASS '(' identifier ')' { $$ = MkExpClass(MkListOne(MkSpecifierName($3.string)), null); FreeIdentifier($3); $$.loc = @$; }
+   | VAARG '(' assignment_expression ',' type_name ')' { $$ = MkExpVaArg($3, $5); $$.loc = @$; }
+   
+   | CLASS_DATA '(' identifier ')' { $$ = MkExpClassData($3); $$.loc = @$; }
+   | database_open
+   | dbfield
+   | dbindex
+   | dbtable
+
+   | '[' argument_expression_list ']' { $$ = MkExpArray($2); $$.loc = @$; }
+   ;
+*/
+   if(peekToken().type == CONSTANT)
+      return ExpConstant::parse();
+   else if(nextToken.type == IDENTIFIER)
+      return ExpIdentifier::parse();
+   else if(nextToken.type == STRING_LITERAL)
+      return ExpString::parse();
+   else
+      return null;
+}
+
+static ASTExpression parsePrimaryExpression()
+{
+   if(peekToken().type == '(')
+   {
+      ExpBrackets exp { };
+      readToken();
+      exp.list = ListExp::parse();
+      if(peekToken().type == ')')
+         readToken();
+      return exp;
+   }
+   else
+      return parseSimplePrimaryExpression();
+}
+
+static ASTExpression parsePostfixExpression()
+{
+   ASTExpression exp = parsePrimaryExpression();
+   while(true)
+   {
+      if(peekToken().type == '[')
+         exp = ExpIndex::parse(exp);
+      else if(nextToken.type == '(')
+         exp = ExpCall::parse(exp);
+      else if(nextToken.type == '.')
+         exp = ExpMember::parse(exp);
+      else if(nextToken.type == PTR_OP)
+         exp = ExpPointer::parse(exp);
+      else if(nextToken.type == INC_OP || nextToken.type == DEC_OP)
+      {
+         readToken();
+         exp = ExpOperation { exp1 = exp, op = token.type };
+      }
+      else
+         break;
+   }
+   return exp;
+}
+
+static ASTExpression parseUnaryExpression()
+{
+   peekToken();
+   if(nextToken.type == INC_OP || nextToken.type == DEC_OP)
+   {
+      readToken();
+      return ExpOperation { op = token.type, exp2 = parseUnaryExpression() };
+   }
+   else if(nextToken.type.isUnaryOperator)
+   {
+      readToken();
+      return ExpOperation { op = token.type, exp2 = ExpCast::parse() };
+   }
+   /*else if(nextToken == SIZEOF)
+   {
+      readToken();
+      return ExpSizeof { };
+   }
+   else if(nextToken == ALIGNOF)
+   {
+      readToken();
+      return ExpSizeof { };
+   }*/
+   else
+      return parsePostfixExpression();
+}
+
+public class ExpConstant : ASTExpression
+{
+   String constant;
+
+   void print()
+   {
+      Print(constant);
+   }
+
+   ExpConstant ::parse()
+   {
+      return { constant = CopyString(readToken().text); };
+   }
+
+   float Compute()
+   {
+      return (float)atof(constant);
+   }
+}
+
+public class ExpString : ASTExpression
+{
+   String string;
+
+   void print()
+   {
+      Print(string);
+   }
+
+   ExpString ::parse()
+   {
+      return { string = CopyString(readToken().text) };
+   }
+}
+
+public class ExpIdentifier : ASTExpression
+{
+   ASTIdentifier identifier;
+
+   void print()
+   {
+      identifier.print();
+   }
+
+   ExpIdentifier ::parse()
+   {
+      return { identifier = ASTIdentifier::parse() };
+   }
+}
+
+public class ExpOperation : ASTExpression
+{
+   TokenType op;
+   ASTExpression exp1, exp2;
+
+   void print()
+   {
+      if(exp1) { exp1.print(); if(exp2) Print(" "); }
+      op.print();
+      if(exp2) { if(exp1) Print(" "); exp2.print(); }
+   }
+
+   ASTExpression ::parse(int prec)
+   {
+      ASTExpression exp = (prec > 0) ? parse(prec-1) : ExpCast::parse();
+      while(isPrecedence(peekToken().type, prec))
+         exp = ExpOperation { exp1 = exp, op = readToken().type, exp2 = (prec > 0) ? parse(prec-1) : ExpCast::parse() };
+      return exp;
+   }
+
+   float Compute()
+   {
+      if(exp1 && exp2)
+      {
+         switch(op)
+         {
+            case '*': return exp1.Compute() * exp2.Compute();
+            case '/': return exp1.Compute() / exp2.Compute();
+            case '-': return exp1.Compute() - exp2.Compute();
+            case '+': return exp1.Compute() + exp2.Compute();
+         }
+      }
+      else if(exp2)
+      {
+         switch(op)
+         {
+            case '-': return -exp2.Compute();
+            case '+': return  exp2.Compute();
+         }
+      }
+      return 0;
+   }
+}
+
+public class ExpAssignment : ExpOperation
+{
+   ASTExpression ::parse()
+   {
+      ASTExpression exp = ExpConditional::parse();
+      if(peekToken().type.isAssignmentOperator)
+         exp = ExpAssignment { exp1 = exp, op = readToken().type, exp2 = ExpAssignment::parse() };
+      return exp;
+   }
+}
+
+public class ExpBrackets : ASTExpression
+{
+public:
+   ListExp list;
+
+   void print()
+   {
+      Print("(");
+      if(list) list.print();
+      Print(")");
+   }
+
+   float Compute()
+   {
+      return (list && list.lastIterator.data) ? list.lastIterator.data.Compute() : 0;
+   }
+}
+
+public class ExpConditional : ASTExpression
+{
+public:
+   ASTExpression condition;
+   ListExp expList;
+   ASTExpression elseExp;
+
+   void print()
+   {
+      if(condition) condition.print();
+      Print(" ? ");
+      if(expList) expList.print();
+      Print(" : ");
+      if(elseExp)
+         elseExp.print();
+   }
+
+   ASTExpression ::parse()
+   {
+      ASTExpression exp = ExpOperation::parse(numPrec-1);
+      if(peekToken().type == '?')
+      {
+         exp = ExpConditional { condition = exp, expList = ListExp::parse() };
+         if(peekToken().type == ':')
+            ((ExpConditional)exp).elseExp = ExpConditional::parse();
+      }
+      return exp;
+   }
+}
+
+public class ExpIndex : ASTExpression
+{
+   ASTExpression exp;
+   ListExp index;
+
+   void print()
+   {
+      if(exp) exp.print();
+      Print("[");
+      if(index) index.print();
+      Print("]");
+   }
+
+   ExpIndex ::parse(ASTExpression e)
+   {
+      ExpIndex exp;
+      readToken();
+      exp = ExpIndex { exp = e, index = ListExp::parse() };
+      if(peekToken().type == ']')
+         readToken();
+      return exp;
+   }
+}
+
+public class ExpMember : ASTExpression
+{
+   ASTExpression exp;
+   ASTIdentifier member;
+   // MemberType memberType;
+   // bool thisPtr;
+
+   void print()
+   {
+      if(exp) exp.print();
+      Print(".");
+      if(member)
+         member.print();
+   }
+
+   ExpMember ::parse(ASTExpression e)
+   {
+      readToken();
+      return { exp = e, member = ASTIdentifier::parse() };
+   }
+}
+
+public class ExpPointer : ExpMember
+{
+   void print()
+   {
+      if(exp) exp.print();
+      Print("->");
+      if(member)
+         member.print();
+   }
+
+   ExpPointer ::parse(ASTExpression e)
+   {
+      readToken();
+      return { exp = e, member = ASTIdentifier::parse() };
+   }
+}
+
+public class ExpCall : ASTExpression
+{
+   ASTExpression exp;
+   ListExp arguments;
+   // Location argLoc;
+
+   void print()
+   {
+      if(exp) exp.print();
+      Print("(");
+      if(arguments) arguments.print();
+      Print(")");
+   }
+
+   ExpCall ::parse(ASTExpression e)
+   {
+      ExpCall exp;
+      readToken();
+      exp = ExpCall { exp = e, arguments = ListExp::parse() };
+      if(peekToken().type == ')')
+         readToken();
+      return exp;
+   }
+}
+
+public class ExpCast : ASTExpression
+{
+   ASTTypeName typeName;
+   ASTExpression exp;
+
+   ASTExpression ::parse()
+   {
+      ASTExpression exp = parseUnaryExpression();
+      // TODO: Deal with cast ambiguity
+      return exp;
+   }
+}
+
+/*   union
+   {
+      Instantiation instance;
+      struct
+      {
+         OldList * specifiers;
+         ASTDeclarator decl;
+      } _classExp;
+      struct
+      {
+         Identifier id;
+      } classData;
+      TypeName typeName;
+      Specifier _class;
+      struct
+      {
+         TypeName typeName;
+         Expression size;
+      } _new;
+      struct
+      {
+         TypeName typeName;
+         Expression size;
+         Expression exp;
+      } _renew;
+      struct
+      {
+         char * table;
+         Identifier id;
+      } db;
+      struct
+      {
+         Expression ds;
+         Expression name;
+      } dbopen;
+      struct
+      {
+         TypeName typeName;
+         Initializer initializer;
+      } initializer;
+      struct
+      {
+         Expression exp;
+         TypeName typeName;
+      } vaArg;
+   };
+};
+*/
+
+/*
+      Instantiation inst;
+      struct
+      {
+         Identifier id;
+         Expression exp;
+      };
+   Specifier extStorage;
+   Symbol symbol;
+   AccessMode declMode;
+*/
+/*
+public class Instantiation : struct
+{
+public:
+   Instantiation prev, next;
+   Location loc;
+   Specifier _class;
+   Expression exp;
+   OldList * members;
+   Symbol symbol;
+   bool fullSet;
+   bool isConstant;
+   byte * data;
+   Location nameLoc, insideLoc;
+   bool built;
+};
+*/
diff --git a/compiler/libec2/src/externals.ec b/compiler/libec2/src/externals.ec
new file mode 100644 (file)
index 0000000..e8c055b
--- /dev/null
@@ -0,0 +1,139 @@
+import "statements"
+
+public class ASTDeclaration : ASTStmtOrDecl
+{
+public:
+   DeclarationType type;
+
+   ASTDeclaration ::parse(SpecsList specs, InitDeclList decls)
+   {
+      if(peekToken().type == ';')
+         readToken();
+      return DeclarationInit { specifiers = specs, declarators = decls };
+   }
+}
+
+public class DeclarationInit : ASTDeclaration
+{
+public:
+   SpecsList specifiers;
+   InitDeclList declarators;
+
+   void print()
+   {
+      if(specifiers)
+      {
+         for(s : specifiers)
+            s.print();
+         Print(" ");
+      }
+      if(declarators)
+         declarators.print();
+      Print(";");
+   }
+}
+
+public class ASTFunctionDefinition : ASTNode
+{
+public:
+   SpecsList specifiers;
+   ASTDeclarator declarator;
+   List<ASTDeclaration> oldStyleDeclarations;
+   StmtCompound body;
+
+   void print()
+   {
+      PrintLn("");
+      if(specifiers) 
+      {
+         for(s : specifiers)
+            s.print();
+         Print(" ");
+      }
+      if(declarator)
+         declarator.print();
+      PrintLn("");
+      if(body)
+         body.print();
+   }
+
+   ASTFunctionDefinition ::parse(SpecsList specs, InitDeclList decls)
+   {
+      ASTFunctionDefinition function { };
+      ASTDeclarator decl = (decls && decls[0]) ? decls[0].declarator : null;
+      if(decl && decls[0]) decls[0].declarator = null;
+      delete decls;
+      function.specifiers = (void *)specs;         // TOFIX: #768
+      function.declarator = decl;
+      function.body = StmtCompound::parse();
+      return function;
+   }
+   /*
+   Class _class;
+   OldList attached;    // For IDE
+   AccessMode declMode;
+
+   Type type;
+   Symbol propSet;
+
+   int tempCount;
+   bool propertyNoThis; // Not used yet; might use to support both this = and return syntax for conversion properties
+   */
+};
+
+/*
+   union
+   {
+      FunctionDefinition function;
+      ClassDefinition _class;
+      Declaration declaration;
+      char * importString;
+      Identifier id;
+      DBTableDef table;
+   };
+   ImportType importType;
+};
+*/
+
+public class AST : ASTList<ASTNode>
+{
+   ASTNode ::ParseExternalDeclaration()
+   {
+      SpecsList specs = SpecsList::parse();
+      InitDeclList decls = InitDeclList::parse();
+
+      if(peekToken().type == '{')
+         return ASTFunctionDefinition::parse(specs, decls);
+      else if(specs || decls)
+         return ASTDeclaration::parse(specs, decls);
+      else
+      {
+         readToken(); // Error
+         return null;
+      }
+   }
+public:
+   AST ::parse()
+   {
+      AST ast = null;
+      while(peekToken().type)
+      {
+         ASTNode n = ParseExternalDeclaration();
+         if(n)
+         {
+            if(!ast) ast = { };
+            ast.Add(n);
+         }
+      }
+      return ast;
+   }
+
+   void print()
+   {
+      for(n : this)
+      {
+         n.print();
+         PrintLn("");
+      }
+   }
+}
diff --git a/compiler/libec2/src/lexing.ec b/compiler/libec2/src/lexing.ec
new file mode 100644 (file)
index 0000000..9fc7a2f
--- /dev/null
@@ -0,0 +1,191 @@
+public import "ecere"
+public import "ec"
+
+public enum TokenType
+{
+   IDENTIFIER = 258, CONSTANT = 259, STRING_LITERAL = 260, SIZEOF = 261,PTR_OP = 262,INC_OP = 263,DEC_OP = 264, LEFT_OP = 265, RIGHT_OP = 266, LE_OP = 267, GE_OP = 268, EQ_OP = 269, NE_OP = 270,
+   AND_OP = 271, OR_OP = 272, MUL_ASSIGN = 273, DIV_ASSIGN = 274, MOD_ASSIGN = 275, ADD_ASSIGN = 276, SUB_ASSIGN = 277, LEFT_ASSIGN = 278, RIGHT_ASSIGN = 279, AND_ASSIGN = 280, XOR_ASSIGN = 281,
+   OR_ASSIGN = 282, TYPE_NAME = 283, TYPEDEF = 284, EXTERN = 285, STATIC = 286, AUTO = 287, REGISTER = 288, CHAR = 289, SHORT = 290, INT = 291, UINT = 292, INT64 = 293, LONG = 294, SIGNED = 295,
+   UNSIGNED = 296, FLOAT = 297, DOUBLE = 298, CONST = 299, VOLATILE = 300, VOID = 301, VALIST = 302, STRUCT = 303, UNION = 304, ENUM = 305, ELLIPSIS = 306, CASE = 307, DEFAULT = 308, IF = 309,
+   SWITCH = 310, WHILE = 311, DO = 312, FOR = 313, GOTO = 314, CONTINUE = 315, BREAK = 316, RETURN = 317, IFX = 318, ELSE = 319, CLASS = 320, THISCLASS = 321, CLASS_NAME = 322, PROPERTY = 323,
+   SETPROP = 324, GETPROP = 325, NEWOP = 326, RENEW = 327, DELETE = 328, EXT_DECL = 329, EXT_STORAGE = 330, IMPORT = 331, DEFINE = 332, VIRTUAL = 333, ATTRIB = 334, PUBLIC = 335, PRIVATE = 336,
+   TYPED_OBJECT = 337, ANY_OBJECT = 338, _INCREF = 339, EXTENSION = 340, ASM = 341, TYPEOF = 342, WATCH = 343, STOPWATCHING = 344, FIREWATCHERS = 345, WATCHABLE = 346, CLASS_DESIGNER = 347,
+   CLASS_NO_EXPANSION = 348, CLASS_FIXED = 349, ISPROPSET = 350, CLASS_DEFAULT_PROPERTY = 351, PROPERTY_CATEGORY = 352, CLASS_DATA = 353, CLASS_PROPERTY = 354, SUBCLASS = 355, NAMESPACE = 356,
+   NEW0OP = 357, RENEW0 = 358, VAARG = 359, DBTABLE = 360, DBFIELD = 361, DBINDEX = 362, DATABASE_OPEN = 363, ALIGNOF = 364, ATTRIB_DEP = 365, __ATTRIB = 366;
+
+   property char { }
+
+   property bool isUnaryOperator
+   {
+      get
+      {
+         return this == '&' || this == '*' || this == '+' || this == '-' || this == '~' || this == '!' || this == DELETE || this == _INCREF;
+      }
+   }
+
+   property bool isAssignmentOperator
+   {
+      get
+      {
+         return this == '='|| this == MUL_ASSIGN || this == DIV_ASSIGN || this == MOD_ASSIGN ||
+               this == ADD_ASSIGN || this == SUB_ASSIGN || this == LEFT_ASSIGN || this == RIGHT_ASSIGN ||
+               this == AND_ASSIGN || this == XOR_ASSIGN || this == OR_ASSIGN;
+      }
+   }
+
+   void print()
+   {
+      if(this < 256)
+         Print((char)this);
+      else
+      {
+         switch(this)
+         {
+            case VOID: Print("void"); break;
+            case CHAR:  Print("char");  break;
+            case SHORT:  Print("short");  break;
+            case INT:  Print("int");  break;
+            case LONG:  Print("long");  break;
+            case INT64:  Print("int64");  break;
+            case UNSIGNED:  Print("unsigned");  break;
+            case SIGNED:  Print("signed");  break;
+            case FLOAT:  Print("float");  break;
+            case DOUBLE:  Print("double");  break;
+
+            case INC_OP: Print("++"); break;
+            case DEC_OP: Print("--"); break;
+            case SIZEOF: Print("sizeof "); break;
+            case LEFT_OP: Print("<<"); break;
+            case RIGHT_OP: Print(">>"); break;
+            case LE_OP: Print("<="); break;
+            case GE_OP: Print(">="); break;
+            case EQ_OP: Print("=="); break;
+            case NE_OP: Print("!="); break;
+            case AND_OP: Print("&&"); break;
+            case OR_OP: Print("||"); break;
+          case MUL_ASSIGN: Print("*="); break;
+          case DIV_ASSIGN: Print("/="); break;
+          case MOD_ASSIGN: Print("%="); break;
+          case ADD_ASSIGN: Print("+="); break;
+          case SUB_ASSIGN: Print("-="); break;
+          case LEFT_ASSIGN: Print("<<="); break;
+          case RIGHT_ASSIGN: Print(">>="); break;
+          case AND_ASSIGN: Print("&="); break;
+          case XOR_ASSIGN: Print("^="); break;
+          case OR_ASSIGN: Print("|="); break;
+         }
+      }
+   }
+};
+
+class Token
+{
+   TokenType type;
+   String text;
+   ~Token()
+   {
+      delete text;
+   }
+}
+
+Token token, nextToken;
+
+int ambiguous, stackPos;
+Array<Token> tokenStack { minAllocSize = 256 };
+
+Token readToken()
+{
+   if(!nextToken) peekToken();
+   delete token;
+   token = nextToken;
+   nextToken = null;
+   return token;
+}
+
+Token peekToken()
+{
+   if(!nextToken)
+   {
+      if(stackPos < tokenStack.count)
+      {
+         nextToken = tokenStack[stackPos++];
+         incref nextToken;
+         if(!ambiguous && stackPos == tokenStack.count)
+         {
+            tokenStack.Free();
+            stackPos = 0;
+         }
+      }
+      else
+      {
+         nextToken = { _refCount = 1 };
+         nextToken.type = (TokenType)LexEc();
+         nextToken.text = CopyString(GetYYText());
+         if(ambiguous)
+         {
+            stackPos++;
+            tokenStack.Add(nextToken);
+            incref nextToken;
+         }
+      }
+   }
+   return nextToken;
+}
+
+int pushAmbiguity()
+{
+   if(!ambiguous && nextToken && stackPos == tokenStack.count)
+   {
+      stackPos++;
+      tokenStack.Add(nextToken);
+      incref nextToken;
+   }
+   ambiguous++;
+   return stackPos - (nextToken ? 1 : 0);
+}
+
+void clearAmbiguity()
+{
+   if(!--ambiguous && stackPos > 0)
+   {
+      int i;
+      for(i = 0; i < stackPos; i++)
+         delete tokenStack[i];
+      if(tokenStack.size > stackPos)
+         memmove(tokenStack.array, tokenStack.array + stackPos, (tokenStack.size - stackPos) * sizeof(Token));
+      tokenStack.size -= stackPos;
+      stackPos = 0;      
+   }
+}
+
+void popAmbiguity(int i)
+{
+   delete token;
+   delete nextToken;
+
+   stackPos = i;
+   clearAmbiguity();
+   token = null;
+   nextToken = null;
+}
+
+public void lexAll()
+{
+   while(readToken())
+   {
+      if(token.type < 256)
+         PrintLn((char)token.type);
+      else
+         PrintLn(token.type, " (", token.text, ")");
+   }
+}
+
+public void initParser(File f)
+{
+   SetFileInput(f);
+   delete token;
+   delete nextToken;
+   tokenStack.size = 0;
+   stackPos = 0;
+   ambiguous = 0;
+}
diff --git a/compiler/libec2/src/specifiers.ec b/compiler/libec2/src/specifiers.ec
new file mode 100644 (file)
index 0000000..14e4a96
--- /dev/null
@@ -0,0 +1,127 @@
+import "astNode"
+
+// Specifiers
+public class ASTSpecifier : ASTNode
+{
+public:
+   SpecifierType type;
+  /*    struct
+      {
+         //ExtDecl extDecl;
+         //Symbol symbol;
+         //OldList * templateArgs;
+      };
+      struct
+      {
+         Identifier id;
+         OldList * list;
+         OldList * baseSpecs;
+         OldList * definitions;
+         bool addNameSpace;
+         Context ctx;
+         ExtDecl extDeclStruct;
+      };
+      Expression expression;
+      NewSpecifier _class;
+      TemplateParameter templateParameter;
+   };
+      */
+};
+
+public class SpecsList : ASTList<ASTSpecifier>
+{
+   SpecsList ::parse()
+   {
+      SpecsList specs = null;
+      bool gotSpec = false;
+      while(true)
+      {
+         peekToken();
+         if(nextToken.type == INT || nextToken.type == CHAR || nextToken.type == VOID)
+         {
+            readToken();
+            if(!specs) specs = { };
+            specs.Add(SpecBase { specifier = token.type });
+            gotSpec = true;
+         }
+         else if(nextToken.type == IDENTIFIER)
+         {
+            bool isType = false;
+            if(isType || !gotSpec)
+            {
+               readToken();
+               if(!specs) specs = { };
+               specs.Add(SpecName { name = CopyString(token.text) });
+               gotSpec = true;
+            }
+            else
+               break;
+         }
+         else
+            break;
+      }
+      return specs;
+   }
+}
+
+public class SpecBase : ASTSpecifier
+{
+   TokenType specifier;
+
+   void print()
+   {
+      specifier.print();
+   }
+}
+
+public class SpecName : ASTSpecifier
+{
+   String name;
+
+   void print()
+   {
+      if(name) Print(name);
+   }
+}
+
+/*
+public class Attribute : struct
+{
+public:
+   Attribute prev, next;
+   Location loc;
+   String attr;
+   Expression exp;
+}
+
+public class Attrib : struct
+{
+public:
+   Location loc;
+   int type;
+   OldList * attribs;
+}
+
+public class ExtDecl : struct
+{
+public:
+   Location loc;
+   ExtDeclType type;
+   union
+   {
+      String s;
+      Attrib attr;
+   };
+}
+*/
+
+/*
+public class Enumerator : struct
+{
+public:
+   Enumerator prev, next;
+   Location loc;
+   Identifier id;
+   Expression exp;
+};
+*/
diff --git a/compiler/libec2/src/statements.ec b/compiler/libec2/src/statements.ec
new file mode 100644 (file)
index 0000000..054d894
--- /dev/null
@@ -0,0 +1,573 @@
+import "expressions"
+import "externals"
+
+public class ASTPropertyWatch : ASTNode
+{
+public:
+   ASTStatement compound;
+   List<ASTIdentifier> properties;
+   bool deleteWatch;
+};
+
+/*
+class AsmField : struct
+{
+   AsmField prev, next;
+   Location loc;
+   char * command;
+   Expression expression;
+};
+*/
+
+// *** Statements ***
+public class ASTStmtOrDecl : ASTNode
+{
+   ASTStmtOrDecl ::parse()
+   {
+      SpecsList specs;
+      InitDeclList decls;
+
+      peekToken();
+      if(nextToken.type == INT || nextToken.type == CHAR || nextToken.type == VOID)
+      {
+         specs = SpecsList::parse();
+         decls = InitDeclList::parse();
+         return ASTDeclaration::parse(specs, decls);
+      }
+      else if(nextToken.type == IDENTIFIER)
+      {
+         int a = pushAmbiguity();
+         specs = SpecsList::parse();
+         decls = InitDeclList::parse();
+         if(specs && decls)
+         {
+            clearAmbiguity();
+            return ASTDeclaration::parse(specs, decls);
+         }
+         popAmbiguity(a);
+      }
+      return ASTStatement::parse();
+   }
+}
+
+public class ASTStatement : ASTStmtOrDecl
+{
+public:
+   StmtType type;
+
+   ASTStatement ::parse()
+   {
+      switch(peekToken().type)
+      {
+         case ';':      readToken(); return { };
+         case '{':      return StmtCompound::parse();
+         case IF:       return StmtIf::parse();
+         case SWITCH:   return StmtSwitch::parse();
+         case DEFAULT:
+         case CASE:     return StmtCase::parse();
+         case WHILE:    return StmtWhile::parse();
+         case DO:       return StmtDoWhile::parse();
+         case FOR:      return StmtFor::parse();
+         case BREAK:    return StmtBreak::parse();
+         case GOTO:     return StmtGoto::parse();
+         case RETURN:   return StmtReturn::parse();
+         case CONTINUE: return StmtContinue::parse();
+         case IDENTIFIER:
+         {
+            ASTStatement stmt;
+            int a = pushAmbiguity();
+            stmt = StmtLabeled::parse();
+            if(stmt)
+            {
+               clearAmbiguity();
+               return stmt;
+            }
+            popAmbiguity(a);
+         }
+         default:       return StmtExpression::parse();
+      }
+   }
+};
+
+public class StmtExpression : ASTStatement
+{
+   ListExp expressions;
+
+   void print()
+   {
+      if(expressions) expressions.print();
+      Print(";");
+   }
+
+   StmtExpression ::parse()
+   {
+      ListExp exp = ListExp::parse();
+      if(exp)
+      {
+         StmtExpression stmt { expressions = exp };
+         if(peekToken().type == ';')
+            readToken();
+         return stmt;      
+      }
+      return null;
+   }
+}
+int indent;
+void PrintIndent()
+{
+   int i;
+   for(i = 0; i < indent; i++)
+   {
+      Print("   ");
+   }
+}
+
+public class StmtCompound : ASTStatement
+{
+   List<ASTDeclaration> declarations;
+   List<ASTStatement> statements;
+   // Context context;
+   // bool isSwitch;
+
+   void print()
+   {
+      PrintLn("{");
+      indent++;
+      if(declarations)
+      {
+         for(d : declarations)
+         {
+            PrintIndent();
+            d.print();
+            PrintLn("");
+         }
+         if(statements)
+            PrintLn("");
+      }
+      if(statements)
+      {
+         for(s : statements)
+         {
+            if(s._class == class(StmtCase))
+               indent = caseIndent;
+            if(s._class != class(StmtLabeled))
+               PrintIndent();
+            s.print();
+            if(s._class == class(StmtExpression)) 
+               PrintLn("");
+         }
+      }
+      indent--;
+      if(indent == caseIndent)
+         indent--;
+      PrintIndent();
+      PrintLn("}");
+   }
+
+   StmtCompound ::parse()
+   {
+      StmtCompound stmt { };
+      if(peekToken().type == '{')
+      {
+         readToken();
+         while(true)
+         {
+            if(peekToken().type == '}')
+            {
+               readToken();
+               break;
+            }
+            else if(!nextToken)
+               break;
+            else
+            {
+               ASTStmtOrDecl sod = ASTStmtOrDecl::parse();
+               if(sod)
+               {
+                  if(eClass_IsDerived(sod._class, class(ASTDeclaration)))
+                  {
+                     if(!stmt.declarations) stmt.declarations = { };
+                     stmt.declarations.Add((ASTDeclaration)sod);
+                  }
+                  else
+                  {
+                     if(!stmt.statements) stmt.statements = { };
+                     stmt.statements.Add((ASTStatement)sod);
+                  }
+               }
+               else
+               {
+                  // ERROR
+                  /*while(readToken())
+                     if(token == ';' || token == '}') break;*/
+                  readToken();
+               }
+            }
+         }
+      }
+      return stmt;
+   }
+}
+
+public class StmtIf : ASTStatement
+{
+   ListExp exp;
+   ASTStatement stmt;
+   ASTStatement elseStmt;
+
+   void print()
+   {
+      Print("if(");
+      if(exp) exp.print();
+      PrintLn(")");
+      if(stmt)
+      {
+         if(stmt._class != class(StmtCompound)) indent++;
+         PrintIndent();
+         stmt.print();
+         if(stmt._class == class(StmtExpression)) PrintLn(""); 
+         if(stmt._class != class(StmtCompound)) indent--;
+      }
+      if(elseStmt)
+      {
+         PrintIndent();
+         Print("else");
+         if(elseStmt._class != class(StmtCompound)) { PrintLn(""); indent++; }
+         PrintIndent();
+         if(elseStmt._class != class(StmtCompound)) elseStmt.print();
+         if(elseStmt._class == class(StmtExpression)) PrintLn(""); 
+         indent--;
+      }      
+   }
+
+   StmtIf ::parse()
+   {
+      StmtIf stmt { };
+      readToken();
+      if(peekToken().type == '(')
+      {
+         readToken();
+         stmt.exp = ListExp::parse();
+         if(peekToken().type == ')') readToken();
+         stmt.stmt = ASTStatement::parse();
+         if(peekToken().type == ELSE)
+         {
+            readToken();
+            stmt.elseStmt = ASTStatement::parse();
+         }
+      }
+      return stmt;
+   }
+}
+
+int caseIndent = -1;
+
+public class StmtSwitch : ASTStatement
+{
+   ListExp exp;
+   ASTStatement stmt;
+
+   void print()
+   {
+      int backCaseIndent = caseIndent;
+      Print("switch(");
+      if(exp) exp.print();
+      PrintLn(")");
+      if(stmt)
+      {
+         caseIndent = indent+1;
+         PrintIndent();
+         stmt.print();
+         indent = caseIndent-1;
+      }
+      caseIndent = backCaseIndent;
+   }
+
+   StmtSwitch ::parse()
+   {
+      StmtSwitch stmt { };
+      readToken();
+      if(peekToken().type == '(')
+      {
+         readToken();
+         stmt.exp = ListExp::parse();
+         if(peekToken().type == ')') readToken();
+         stmt.stmt = ASTStatement::parse();
+      }
+      return stmt;
+   }
+}
+
+public class StmtLabeled : ASTStatement
+{
+   ASTIdentifier id;
+   ASTStatement stmt;
+
+   void print()
+   {
+      if(id) id.print();
+      PrintLn(":");
+      if(stmt) stmt.print();
+   }
+
+   StmtLabeled ::parse()
+   {
+      ASTIdentifier id = ASTIdentifier::parse();
+      if(peekToken().type == ':')
+         return StmtLabeled { id = id, stmt = ASTStatement::parse() };
+      delete id;
+      return null;
+   }
+}
+
+public class StmtCase : ASTStatement
+{
+   ASTExpression exp;
+   ASTStatement stmt;
+
+   void print()
+   {
+      if(exp)
+      {
+         Print("case ");
+         exp.print();
+         PrintLn(":");
+      }
+      else
+         PrintLn("default:");
+      if(stmt)
+      {
+         if(stmt._class != class(StmtCompound)) indent++;
+         PrintIndent();
+         stmt.print();
+         if(stmt._class == class(StmtExpression)) PrintLn(""); 
+      }
+   }
+
+   StmtCase ::parse()
+   {
+      StmtCase stmt { };
+      if(readToken().type == CASE)
+         stmt.exp = ExpConditional::parse();
+      if(peekToken().type == ':')
+      {
+         readToken();
+         stmt.stmt = ASTStatement::parse();
+      }
+      return stmt;
+   }
+}
+
+public class StmtWhile : ASTStatement
+{
+   ListExp exp;
+   ASTStatement stmt;
+
+   StmtWhile ::parse()
+   {
+      StmtWhile stmt { };
+      readToken();
+      if(peekToken().type == '(')
+      {
+         readToken();
+         stmt.exp = ListExp::parse();
+         if(peekToken().type == ')') readToken();
+         stmt.stmt = ASTStatement::parse();
+      }
+      return stmt;
+   }
+}
+
+public class StmtDoWhile : ASTStatement
+{
+   ListExp exp;
+   ASTStatement stmt;
+
+   StmtDoWhile ::parse()
+   {
+      StmtDoWhile stmt { };
+      readToken();
+      stmt.stmt = ASTStatement::parse();
+      if(peekToken().type == WHILE)
+      {
+         readToken();
+         if(peekToken().type == '(')
+         {
+            readToken();
+            stmt.exp = ListExp::parse();
+            if(peekToken().type == ')') readToken();
+         }
+         if(peekToken().type == ';') readToken();
+      }
+      return stmt;
+   }
+}
+
+public class StmtFor : ASTStatement
+{
+   ASTStatement init;
+   ASTStatement check;
+   ListExp increment;
+   ASTStatement stmt;
+
+   void print()
+   {
+      Print("for(");
+      if(init)
+         init.print();
+      if(check)
+      {
+         Print(" ");
+         check.print();
+      }
+      if(increment)
+      {
+         Print(" ");
+         increment.print();
+      }
+      PrintLn(")");
+      
+      if(stmt)
+      {
+         if(stmt._class != class(StmtCompound)) indent++;
+         PrintIndent();
+         stmt.print();
+         if(stmt._class == class(StmtExpression)) PrintLn(""); 
+         if(stmt._class != class(StmtCompound)) indent--;
+      }
+   }
+
+   StmtFor ::parse()
+   {
+      StmtFor stmt { };
+      readToken();
+      if(peekToken().type == '(')
+      {
+         readToken();
+         stmt.init = ASTStatement::parse();
+         stmt.check = ASTStatement::parse();
+         stmt.increment = ListExp::parse();
+         if(peekToken().type == ')')
+         {
+            readToken();
+            stmt.stmt = ASTStatement::parse();
+         }      
+      }
+      return stmt;
+   }
+}
+
+public class StmtBreak : ASTStatement
+{
+   void print()
+   {
+      PrintLn("break;");
+   }
+
+   StmtBreak ::parse()
+   {
+      readToken();
+      if(peekToken().type == ';') readToken();
+      return { };
+   }
+}
+
+public class StmtContinue : ASTStatement
+{
+   void print()
+   {
+      PrintLn("continue;");
+   }
+
+   StmtContinue ::parse()
+   {
+      readToken();
+      if(peekToken().type == ';') readToken();
+      return { };
+   }
+}
+
+public class StmtReturn : ASTStatement
+{
+   ListExp exp;
+   void print()
+   {
+      Print("return");
+      if(exp)
+      {
+         Print(" ");
+         exp.print();
+      }
+      ::PrintLn(";");
+   }
+
+   StmtReturn ::parse()
+   {
+      StmtReturn stmt { };
+      readToken();
+      if(peekToken().type != ';') stmt.exp = ListExp::parse();
+      if(peekToken().type == ';') readToken();
+      return stmt;
+   }
+}
+
+public class StmtGoto : ASTStatement
+{
+   ASTIdentifier id;
+
+   void print()
+   {
+      Print("goto ");
+      if(id) id.print();
+      ::PrintLn(";");
+   }
+
+   StmtGoto ::parse()
+   {
+      StmtGoto stmt { };
+      readToken();
+      stmt.id = ASTIdentifier::parse();
+      if(peekToken().type == ';') readToken();
+      return stmt;
+   }
+}
+
+public class StmtAsm : ASTStatement
+{
+   ASTSpecifier spec;
+   String statements;
+   List<String> inputFields;
+   List<String> outputFields;
+   List<String> clobberedFields;
+}
+
+public class StmtWatch : ASTStatement
+{
+   ASTExpression watcher, object;
+   List<ASTPropertyWatch> watches;
+}
+
+public class StmtFireWatch : ASTStatement
+{
+   ASTExpression watcher, object;
+   List<ASTIdentifiers> watches;
+}
+
+public class StmtStopWatching : ASTStatement
+{
+   ASTExpression watcher, object;
+   List<ASTIdentifiers> watches;
+}
+
+public class StmtForEach : ASTStatement
+{
+   Identifier id;
+   ListExp exp;
+   ListExp filter;
+   Statement stmt;
+}
+
+public class StmtDecl : ASTStatement
+{
+   Declaration decl;
+}
diff --git a/compiler/libec2/test.ec b/compiler/libec2/test.ec
new file mode 100644 (file)
index 0000000..7db260e
--- /dev/null
@@ -0,0 +1,61 @@
+int a;
+
+int SomeFunction(int * p)
+{
+   int b[3][4] =
+   {
+      { 1, 0, 0, 0 },
+      { 0, 1, 0, 0 },
+      { 0, 0, 1, 0 }
+   };
+   int c, d, e = 4;
+   String name = "Foo";
+   b * a;
+
+   b = ((a + 3) * a) - (3.1415 * 180 / a);
+   a = b = 5*(2 + 10);
+
+again:
+   switch(a)
+   {
+      case 0: PrintLn("0"); printf(""); break;
+      case 1: PrintLn("1"); printf(""); break;
+      case 2: PrintLn("2"); printf(""); break;
+      case 3:
+         switch(b)
+         {
+            case 4:
+               PrintLn("Cool");
+               break;
+            case 5:
+               PrintLn("Awesome");
+               break;
+            default:
+               PrintLn("Unbelievable");
+         }
+         break;
+   }
+   if(!strcmp(name, "Foo"))
+      goto again;
+
+   for(c = 0; c < 10; c++)
+      PrintLn(c);
+   
+   if(a) if(b) s; else s2;
+
+   if(a == 4)
+//   {
+      if(a == 3)
+         PrintLn("3!");
+//   }
+      else
+         PrintLn("not 4, nor 3!");
+   c = !b || a ^ b == a < b;
+   b = 4 << 5 + a[b]->cool("nice") & 32;
+
+   return eC.awesomeness <<= 1;
+}
+
+//3 + 4 * 2
+//1 * 2 * 3 * 4
+//-10 *23