--- /dev/null
+{
+ "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" : [
+
+ ]
+}
--- /dev/null
+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 {};
--- /dev/null
+{
+ "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" : [
+
+ ]
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+/*
+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;
+};
+*/
--- /dev/null
+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, ',');
+ }
+}
--- /dev/null
+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;
+};
+*/
--- /dev/null
+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("");
+ }
+ }
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+};
+*/
--- /dev/null
+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;
+}
--- /dev/null
+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